/*
 * This software is distributed under following license based on modified BSD
 * style license.
 * ----------------------------------------------------------------------
 * 
 * Copyright 2009 The Nimbus2 Project. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer. 
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE NIMBUS PROJECT ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 * NO EVENT SHALL THE NIMBUS PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * The views and conclusions contained in the software and documentation are
 * those of the authors and should not be interpreted as representing official
 * policies, either expressed or implied, of the Nimbus2 Project.
 */
package jp.ossc.nimbus.service.journal;

import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;

import jp.ossc.nimbus.beans.ServiceNameEditor;
import jp.ossc.nimbus.core.Utility;
import jp.ossc.nimbus.core.ServiceBase;
import jp.ossc.nimbus.core.ServiceManagerFactory;
import jp.ossc.nimbus.core.ServiceName;
import jp.ossc.nimbus.service.journal.JournalEditor;
import jp.ossc.nimbus.util.ClassMappingTree;

/**
 * エディターファインダーサービスの実装クラス。<p>
 * 
 * @author M.Takata
 */
public class DefaultEditorFinderService extends ServiceBase
 implements EditorFinder, DefaultEditorFinderServiceMBean{
    
    private static final long serialVersionUID = 3461059713016112562L;

    /** 上位リポジトリ */
    protected EditorFinder parentEditorFinder;
    
    /** 上位リポジトリサービス名  */
    protected ServiceName parentEditorFinderServiceName;
    
    /** エディタメンバー指定プロパティ */
    protected Map<String, Object> journalEditorMapping;
    
    /** エディタツリー管理 */
    protected ClassMappingTree<Map<String, JournalEditor>> journalEditorRepository;
    
    public void setJournalEditorMapping(Map<String, Object> prop){
        journalEditorMapping = prop;
    }
    public Map<String, Object> getJournalEditorMapping(){
        return journalEditorMapping;
    }
    
    public void setParentEditorFinderServiceName(ServiceName name){
        parentEditorFinderServiceName = name;
    }
    public ServiceName getParentEditorFinderServiceName(){
        return parentEditorFinderServiceName;
    }
    
    public void setParentEditorFinder(EditorFinder finder){
        parentEditorFinder = finder;
    }
    
    public void createService() throws Exception{
        journalEditorRepository = new ClassMappingTree<Map<String, JournalEditor>>();
    }
    
    public void startService() throws Exception{
        //上位リポジトリの取得
        if(parentEditorFinderServiceName != null){
            parentEditorFinder = ServiceManagerFactory.getServiceObject(
                parentEditorFinderServiceName
            );
        }
        
        if(journalEditorMapping == null || journalEditorMapping.size() == 0){
            throw new IllegalArgumentException("JournalEditorMapping must be specified.");
        }
        ServiceNameEditor editor = new ServiceNameEditor();
        editor.setServiceManagerName(getServiceManagerName());
        //自分が管理するエディターサービスの設定
        Iterator<String> iterator = journalEditorMapping.keySet().iterator();
        while(iterator.hasNext()){
            String classAndKey = iterator.next();
            String key = null;
            String clsName = null;
            final int index = classAndKey.indexOf(',');
            if(index == -1){
                clsName = classAndKey;
            }else{
                clsName = classAndKey.substring(0, index);
                if(index != classAndKey.length() - 1){
                    key = classAndKey.substring(index + 1);
                }
            }
            
            Class<?> cls = Utility.convertStringToClass(clsName);
            
            Object value = journalEditorMapping.get(classAndKey);
            JournalEditor journalEditor = null;
            if(value instanceof String){
                String nameStr = (String)value;
                editor.setAsText(nameStr);
                final ServiceName name = (ServiceName)editor.getValue();
                journalEditor = ServiceManagerFactory.getServiceObject(name);
            }else if(value instanceof JournalEditor){
                journalEditor = (JournalEditor)value;
            }
            
            Map<String, JournalEditor> keyEditorMap = journalEditorRepository.getValueOf(cls);
            if(keyEditorMap == null){
                keyEditorMap = new HashMap<String, JournalEditor>();
                journalEditorRepository.add(cls, keyEditorMap);
            }
            keyEditorMap.put(key, journalEditor);
        }
        
    }
    
    public void stopService() throws Exception{
        journalEditorRepository.clear();
    }
    
    public void destroyService() throws Exception{
        parentEditorFinder = null;
        parentEditorFinderServiceName = null;
        journalEditorMapping = null;
        journalEditorRepository = null;
    }
    
    public JournalEditor findEditor(Class<?> paramClass){
        return findEditor(null, paramClass);
    }
    
    public JournalEditor findEditor(Object paramObj){
        return findEditor(null, paramObj);
    }
    
    public JournalEditor findEditor(String key, Class<?> paramClass){
        Map<String, JournalEditor> keyEditorMap
            = journalEditorRepository.getValue(paramClass);
        if(keyEditorMap == null){
            if(parentEditorFinder != null){
                return parentEditorFinder.findEditor(key, paramClass);
            }else{
                return null;
            }
        }
        JournalEditor ret = keyEditorMap.get(key);
        if(ret == null && key != null){
            ret = keyEditorMap.get(null);
        }
        if(ret==null && parentEditorFinder != null){
            ret = parentEditorFinder.findEditor(key, paramClass);
        }
        return ret;
    }
    
    public JournalEditor findEditor(String key, Object paramObj){
        Class<?> cls = paramObj != null ? paramObj.getClass() : null;
        return this.findEditor(key, cls) ;
    }
}
