/*******************************************************************************
 * Copyright (c) 2014 Elphel, Inc.
 * Copyright (c) 2006 Elphel, Inc and Excelsior, LLC.
 * This file is a part of VDT plug-in.
 * VDT plug-in is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * VDT plug-in is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 *  Additional permission under GNU GPL version 3 section 7:
 * If you modify this Program, or any covered work, by linking or combining it
 * with Eclipse or Eclipse plugins (or a modified version of those libraries),
 * containing parts covered by the terms of EPL/CPL, the licensors of this
 * Program grant you additional permission to convey the resulting work.
 * {Corresponding Source for a non-source form of such a combination shall
 * include the source code for the parts of Eclipse or Eclipse plugins used
 * as well as that of the covered work.}
 *******************************************************************************/
package com.elphel.vdt.ui.options;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;

import com.elphel.vdt.core.tools.config.xml.XMLConfig;
import com.elphel.vdt.core.tools.contexts.Context;
import com.elphel.vdt.core.tools.params.ParamGroup;
import com.elphel.vdt.core.tools.params.Parameter;
import com.elphel.vdt.core.tools.params.types.ParamType;
import com.elphel.vdt.core.tools.params.types.ParamTypeBool;
import com.elphel.vdt.core.tools.params.types.ParamTypeEnum;
import com.elphel.vdt.core.tools.params.types.ParamTypeNumber;
import com.elphel.vdt.core.tools.params.types.ParamTypeString;
import com.elphel.vdt.ui.options.component.BoolComponent;
import com.elphel.vdt.ui.options.component.ComboComponent;
import com.elphel.vdt.ui.options.component.Component;
import com.elphel.vdt.ui.options.component.DirComponent;
import com.elphel.vdt.ui.options.component.DirListComponent;
import com.elphel.vdt.ui.options.component.FileComponent;
import com.elphel.vdt.ui.options.component.FileListComponent;
import com.elphel.vdt.ui.options.component.LabelComponent;
import com.elphel.vdt.ui.options.component.NumberComponent;
import com.elphel.vdt.ui.options.component.StringListComponent;
import com.elphel.vdt.ui.options.component.TextComponent;

/**
 * Fills in a panel with controls for editing option of the context.
 * 
 * Created: 17.03.2006
 * @author  Lvov Konstantin
 */

public class OptionsBlock {

    protected final Context context;

    private Composite parent;
	
	private Composite tabComposites[];
    private ScrolledComposite scrolledComposite[];
    
    private TabItem tabItems[];
    private TabFolder tabFolder;

    private HashMap<Parameter, Component> components = new HashMap<Parameter, Component>();
    private List<Component> activeComponents = new ArrayList<Component>();
    
    private ParameterValueChangeListener changeListener;
    
    public OptionsBlock(Composite parent, Context context) {
        this.parent  = parent;
		this.context = context;
		createControl(parent);
        for (Parameter param :  context.getParams())
            param.checkDependentParametersPresents(context.getParams());
	}

	public void performApply() {
        Iterator<Entry<Parameter, Component>> i = components.entrySet().iterator(); 
        while (i.hasNext()) {
            Component component = i.next().getValue();
            component.performApply();
        }
	}

	private void createControl(Composite parent) {
        ParamGroup paramGroups[] = getParamGroups();
        tabComposites = new Composite[paramGroups.length];
        scrolledComposite = new ScrolledComposite[paramGroups.length];
        if (paramGroups.length==0)
        	return;
        if (paramGroups.length > 1)
            createTabFolder(parent, paramGroups);
        else
            createGroupPanel(parent, paramGroups[0]);
            
        // add property controls
        changeListener = new ParameterValueChangeListener();
        addProperties(paramGroups);
        
        for (int i = 0; i < paramGroups.length; i++) {
            scrolledComposite[i].setContent(tabComposites[i]);
            scrolledComposite[i].setMinSize(tabComposites[i].computeSize(SWT.DEFAULT, SWT.DEFAULT));
        }
	} // createControl()

    private void createGroupPanel(Composite parent, ParamGroup paramGroup) {
        ScrolledComposite sc = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL);
        sc.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
        sc.setExpandHorizontal(true);
        sc.setExpandVertical(true);

        Group panel = new Group(sc, SWT.NONE);
        
        GridLayout layout = new GridLayout(2, false);
        layout.marginHeight = 3;
        layout.marginWidth = 3;
        layout.verticalSpacing = 0;
        layout.horizontalSpacing = 5;
        panel.setLayout(layout);

        GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
        panel.setLayoutData(data);
        
        panel.setText(paramGroup.getLabel());
        
        tabComposites[0] = panel;
        scrolledComposite[0] = sc;
    } // createGroupPanel()
    
    private void createTabFolder(Composite parent, ParamGroup paramGroups[]) {
        tabFolder = new TabFolder(parent, SWT.NONE);
        tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        tabItems  = new TabItem[paramGroups.length];
        
        for(int i = 0; i < paramGroups.length; i++) {
            tabItems[i] = new TabItem(tabFolder, SWT.NONE);
            tabItems[i].setText(paramGroups[i].getLabel());
        }

        for (int i = 0; i < paramGroups.length; i++) {
            ScrolledComposite sc = new ScrolledComposite(tabFolder, SWT.H_SCROLL | SWT.V_SCROLL);
            sc.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
            sc.setExpandHorizontal(true);
            sc.setExpandVertical(true);

            GridLayout layout = new GridLayout(2, false);
            layout.marginHeight = 3;
            layout.marginWidth = 3;
            layout.verticalSpacing = 0;
            layout.horizontalSpacing = 5;

            GridData tabGridData = new GridData(SWT.FILL, SWT.FILL, true, false);

            Composite panel = new Composite(sc, SWT.NONE);
            
            panel.setLayout(layout);
            panel.setLayoutData(tabGridData);

            tabComposites[i] = panel;
            scrolledComposite[i] = sc;
            tabItems[i].setControl(sc);
        }
    } // createTabFolders()

    protected Component createComponent(Parameter param) {
        Component component = null;
        ParamType paramType = (param==null)?null:param.getType();
        
        if (param == null) {
            component = new LabelComponent(param);            
        } else if (paramType instanceof ParamTypeNumber) {
            component = new NumberComponent(param);            
        } else if (paramType instanceof ParamTypeBool) {
            component = new BoolComponent(param);            
        } else if (paramType instanceof ParamTypeString) {
            if (((ParamTypeString)paramType).getKind() == ParamTypeString.KIND.FILE)
                component = paramType.isList() ? new FileListComponent(param) 
                                               : new FileComponent(param);            
            else if (((ParamTypeString)paramType).getKind() == ParamTypeString.KIND.DIR)
                component = paramType.isList() ? new DirListComponent(param) 
                                               : new DirComponent(param);            
            else
                component = paramType.isList() ? new StringListComponent(param) 
                                               : new TextComponent(param);            
        } else if (paramType instanceof ParamTypeEnum) {
            component = new ComboComponent(param);            
        } else {
            System.out.println("Param type " + param.getType().getName() + " unknown (not implemented?)");
        }
        if (param!=null) { // Andrey
        	components.put(param, component);
        }
        return component;
    } // createComponent()
    
    private ParamGroup[] getParamGroups() {
        if (context == null)
            return new ParamGroup[0];
        
        List<ParamGroup> paramGroups = context.getVisibleParamGroups();
        return (ParamGroup[]) paramGroups.toArray(new ParamGroup[paramGroups.size()]);
    }
    
    protected void addProperties(ParamGroup paramGroups[]) {
        activeComponents.clear();
        for (int i = 0; i < paramGroups.length; i++) {
            ParamGroup paramGroup = paramGroups[i];
            
            for (Iterator<String> pi = paramGroup.getParams().iterator(); pi.hasNext();) {
                String paramID = (String)pi.next();
                Component component;

                if (paramID.equals(XMLConfig.PARAMGROUP_SEPARATOR)){
                	component = createComponent(null); // will create horizontal separator?
                    component.createControl(tabComposites[i]);
                	continue;
                } else {
                	//
                	Parameter param = context.findParam(paramID);
                	if (!param.isVisible())
                		continue;
                	component = components.get(param);
                	if (component == null)
                		component = createComponent(param);
                	if (component == null)
                		continue;
                	
                }
                activeComponents.add(component);
                //              component.setPreferenceStore(store);
                component.createControl(tabComposites[i]);
                component.setChangeListener(changeListener);
            }
        }
    } // addProperties()
    
    
    private void disposeControl() {
        for (Component component : activeComponents) {
            component.suspendControl();
        }
        Control[] controls = parent.getChildren();
        for (int i = 0; i < controls.length; i++) {
            if (! controls[i].isDisposed())
                controls[i].dispose();
        }
    } // disposeControl()
    
    private void activateControl(Component selected) {
        if (selected != null) {
            selected.resumeControl();
            selected.setFocus();
        }
        for (Component component : activeComponents) {
            component.resumeControl();
        }
        if (selected != null) {
            selected.setFocus();
        }
    }
    
    //-------------------------------------------------------------------------
    private class ParameterValueChangeListener implements Component.ChangeListener {

        public void valueChanged(Component componenet) {
//            System.out.println("");
//            System.out.println("");
//            System.out.println("OptionsBlock.valueChanged: start");
            if ((parent != null) && ! parent.isDisposed()) {
                parent.setRedraw(false);
                int selectedTab = 0;
                if (tabFolder != null)
                    selectedTab = tabFolder.getSelectionIndex();
                disposeControl();
                createControl(parent);
                parent.layout();
                if (tabFolder != null) {
                    tabFolder.setSelection(selectedTab);
                }
                activateControl(componenet);
                parent.setRedraw(true);
            }
//            System.out.println("OptionsBlock.valueChanged: end");
        }
        
    } // class ParameterValueChangeListener
    
} // class OptionsBlock