/*
 * Created on 2005-03-17
 *
 * Part of the Symbian development plug-in for Eclipse
 * Copyright (C) Mikołaj Zalewski, 2005
 */
package pl.zalewski.mikolaj.symbdev.ui.mmpedit;

import java.io.IOException;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.TableWrapData;

import pl.zalewski.mikolaj.symbdev.SymbdevPlugin;
import pl.zalewski.mikolaj.symbdev.SymbianSDKEntry;
import pl.zalewski.mikolaj.symbdev.core.mmpmodel.IAIFDeclaration;
import pl.zalewski.mikolaj.symbdev.core.mmpmodel.IMMPModel;
import pl.zalewski.mikolaj.symbdev.core.mmpmodel.MMPFileReference;
import pl.zalewski.mikolaj.symbdev.templates.ISubstitutionOptionsWizardPage;
import pl.zalewski.mikolaj.symbdev.templates.UidAndCaptionWizardPage;
import pl.zalewski.mikolaj.symbdev.ui.SymbdevImages;
import pl.zalewski.mikolaj.symbdev.ui.internal.widgets.DirectoryDialog;
import pl.zalewski.mikolaj.symbdev.utils.MiscUtils;
import pl.zalewski.mikolaj.symbdev.wizards.NewTemplatedFileWizard;

/**
 * This class implements the section with a tree of extra files
 * (resources/AIF/MBMs) in the MMP file (as seen on the Extras page)
 * 
 * @author mikolaj
 */
public class ExtraTree extends MMPSectionPart {

    protected final String AIF_TEMPLATE_FILENAME="templates/files/aif.rss";
    protected final String RESOURCE_TEMPLATE_FILENAME="templates/files/resource.rss";
    
    public static final int ELEMENT_NONE=0;
    public static final int ELEMENT_RESOURCE=1;
    public static final int ELEMENT_SYSTEM_RESOURCE=2;
    public static final int ELEMENT_AIF=3;
    public static final int ELEMENT_MBM=4;
    
    public ExtraTree(Composite parent, FormToolkit toolkit, IMMPModel model,
            SymbianSDKEntry sdk, IPath currentDir, Listener selectionListener,
            IProject project) {
        super(parent, toolkit, "Extra tagets",
                "Apart from the main executable the MMP file may " +
                "also contain definitions of resources files, AIF " +
                "and Multi-Bitmap files to build.", 2);
        fModel=model;
        fSDK=sdk;
        fProject=project;
        fCurrentDir=currentDir;
        fItemsTree=new Tree(fContainer, SWT.NONE);
        fSelectionListener=selectionListener;
        toolkit.adapt(fItemsTree);
        TableWrapData td=new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.FILL_GRAB);
        td.heightHint=200;
        fItemsTree.setLayoutData(td);

        fResourcesRoot=new TreeItem(fItemsTree, SWT.NONE);
        fResourcesRoot.setText("Resources files");
        fResourcesRoot.setImage(SymbdevImages.DESC_RESOURCE_GROUP.createImage());
        fSystemResourcesRoot=new TreeItem(fItemsTree, SWT.NONE);
        fSystemResourcesRoot.setText("System resources files");
        fSystemResourcesRoot.setImage(SymbdevImages.DESC_RESOURCE_GROUP.createImage());
        fAIFRoot=new TreeItem(fItemsTree, SWT.NONE);
        fAIFRoot.setText("Application Information File (AIF)");
        fAIFRoot.setImage(SymbdevImages.DESC_AIF_ICON.createImage());
        fMBMRoot=new TreeItem(fItemsTree, SWT.NONE);
        fMBMRoot.setText("Multi-Bitmap files (MBMs)");
        fMBMRoot.setImage(SymbdevImages.DESC_MBM_ICON.createImage());
        
        Composite buttons=toolkit.createComposite(fContainer);
        td=new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE);
        buttons.setLayoutData(td);
        GridLayout gl=new GridLayout(1, true);
        buttons.setLayout(gl);
        fAdd=toolkit.createButton(buttons, "Add...", SWT.PUSH);
        fAdd.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        fAdd.addListener(SWT.Selection, new Listener() {
            public void handleEvent(org.eclipse.swt.widgets.Event e) {
                addClicked();
            }			
        });
        fCreate=toolkit.createButton(buttons, "Create...", SWT.PUSH);
        fCreate.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        fCreate.addListener(SWT.Selection, new Listener() {
            public void handleEvent(org.eclipse.swt.widgets.Event e) {
                createClicked();
            }			
        });
        fRemove=toolkit.createButton(buttons, "Remove", SWT.PUSH);
        fRemove.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        fRemove.addListener(SWT.Selection, new Listener() {
            public void handleEvent(org.eclipse.swt.widgets.Event e) {
                removeClicked();
            }			
        });
        
        fItemsTree.addListener(SWT.Selection, new Listener() {
            public void handleEvent(org.eclipse.swt.widgets.Event e) {
                selectionChanged();
            }			
        });
        
        resourcesChanged(false);
        resourcesChanged(true);
        aifChanged();
        
        contentCreated();
        
        fResourceListener=new Listener() {
            public void handleEvent(org.eclipse.swt.widgets.Event e) {
                resourcesChanged(false);
            }			
        };
        fModel.addChangeListener(IMMPModel.CHANGE_RESOURCES, fResourceListener);
        fSystemResourceListener=new Listener() {
            public void handleEvent(org.eclipse.swt.widgets.Event e) {
                resourcesChanged(true);
            }			
        };
        fModel.addChangeListener(IMMPModel.CHANGE_SYSTEM_RESOURCES, fSystemResourceListener);
        fAIFListener=new Listener() {
            public void handleEvent(org.eclipse.swt.widgets.Event e) {
                aifChanged();
            }			
        };
        fModel.addChangeListener(IMMPModel.CHANGE_AIF, fAIFListener);
    }
    
    protected void enableButtons()
    {
        TreeItem[] sel=fItemsTree.getSelection();
        if (sel.length==0)
        {
            fAdd.setEnabled(false);
            fCreate.setEnabled(false);
            fRemove.setEnabled(false);
            return;
        }
        if (sel[0].getParentItem()!=null) {
            fAdd.setEnabled(true);
        	fCreate.setEnabled(true);
        	fRemove.setEnabled(true);
        	return;
        }

        if (sel[0]==fAIFRoot) {
            fAdd.setEnabled(fModel.getAIFDeclaration()==null);
            fCreate.setEnabled(fModel.getAIFDeclaration()==null);
            fRemove.setEnabled(fModel.getAIFDeclaration()!=null);
            return;
        }
        
        fAdd.setEnabled(true);
        fCreate.setEnabled(sel[0]!=fMBMRoot);
        fRemove.setEnabled(false);
    }
    
    int getItemPos(TreeItem item)
    {
        TreeItem[] items=item.getParentItem().getItems();
        int pos;
        for (pos=0; pos<items.length; pos++)
            if (items[pos]==item)
                return pos;
        return -1;     
    }
    
    int getItemType(TreeItem item)
    {
        TreeItem parent=item.getParentItem();
        if (parent==fResourcesRoot)
            return ELEMENT_RESOURCE;
        if (parent==fSystemResourcesRoot)
            return ELEMENT_SYSTEM_RESOURCE;
        if (item==fAIFRoot)     // AIF is special - no child items
            return ELEMENT_AIF;
        if (parent==fMBMRoot)
            return ELEMENT_MBM;
        return ELEMENT_NONE;
    }
    
    protected void selectionChanged()
    {
        enableButtons();
        TreeItem[] sel=fItemsTree.getSelection();
        Event e=new Event();
        if (sel.length==1)
        {
            if (sel[0].getParentItem()!=null)
                e.detail=getItemPos(sel[0]);
            e.count=getItemType(sel[0]);
            if (e.count==ELEMENT_AIF && fModel.getAIFDeclaration()==null)
                e.count=ELEMENT_NONE;
        } else e.count=ELEMENT_NONE;
        if (fSelectionListener!=null)
            fSelectionListener.handleEvent(e);
    }
    
    TreeItem getSelectionType()
    {
        TreeItem[] sel=fItemsTree.getSelection();
        if (sel.length==0)
            return null;
        TreeItem type=sel[0];
        if (type.getParentItem()!=null)
            type=type.getParentItem(); 
        return type;
    }
    
    int getSelectionPos()
    {
        TreeItem[] sel=fItemsTree.getSelection();
        if (sel.length==0)
            return -1;
        TreeItem item=sel[0];
        if (item.getParentItem()==null)
            if (item==fAIFRoot)
                return 0;
            	else return -1;
        return getItemPos(item);
    }

    private void addAIFFile(IPath path) {
        String target=fModel.getTargetFilename();
        if (target==null)
            target="filename";
        int dot=target.lastIndexOf('.');
        if (dot!=-1) target=target.substring(0, dot);
        target=target+".aif";
        try {
            fModel.createAIFDeclaration(path, target);
        } catch (CoreException e) {
            SymbdevPlugin.showError(e, "Error creating AIF declaration",
                    getSection().getShell());
        }
    }
    
    protected void addClicked()
    {
        TreeItem type=getSelectionType();
        if (type==fResourcesRoot || type==fSystemResourcesRoot)
        {
            DirectoryDialog dlg=new DirectoryDialog(getSection().getShell(),
                    fSDK, fCurrentDir, false);
            if (!dlg.execute())
                return;
            String path=dlg.getResult();
            IPath absolutePath=fCurrentDir.append(path);
            try {
                if (type==fResourcesRoot)
                    fModel.addResource(absolutePath);
                	else fModel.addSystemResource(absolutePath);
            }
            catch (CoreException e) {
                SymbdevPlugin.showError(e, "Error while adding resource",
                        getSection().getShell());
            }
        } else if (type==fAIFRoot && fModel.getAIFDeclaration()==null) {
            DirectoryDialog dlg=new DirectoryDialog(getSection().getShell(),
                    fSDK, fCurrentDir, false);
            if (dlg.execute())
                addAIFFile(dlg.getResultPath());
        }
    }

    protected IFile createResource(String templateName, ISubstitutionOptionsWizardPage content) {
        try {
	        NewTemplatedFileWizard wiz=new NewTemplatedFileWizard(SymbdevPlugin.getDefault().
	                openStream(new Path(templateName), true));
	        wiz.init(PlatformUI.getWorkbench(), new StructuredSelection(fProject));
	        wiz.setWizardContentProvider(content);
	        wiz.setDescrption("Create a new file - usually with a *.rss extention");
	        WizardDialog dlg=new WizardDialog(getSection().getShell(), wiz);
	        dlg.open();
	        return wiz.getResultFile();
        }
        catch (IOException e) {
            SymbdevPlugin.showError(new CoreException(
                    SymbdevPlugin.createErrorStatus(
                            SymbdevPlugin.ERROR_IO_ACCESS,
                            "Error opening template", e)), 
                    "Error opening template", getSection().getShell());
            return null;
        }
    }
    
    protected void createClicked() {
        TreeItem type=getSelectionType();
        if (type==fResourcesRoot || type==fSystemResourcesRoot)
        {
            IFile result=createResource(RESOURCE_TEMPLATE_FILENAME, null);
	        if (result==null)
	            return ;
            try {
                if (type==fResourcesRoot)
                    fModel.addResource(result.getLocation());
                	else fModel.addSystemResource(result.getLocation());
            }
            catch (CoreException e) {
                SymbdevPlugin.showError(e, "Error while adding resource into the MMP file",
                        getSection().getShell());
            }
        } else if (type==fAIFRoot && fModel.getAIFDeclaration()==null) {
            UidAndCaptionWizardPage page=new UidAndCaptionWizardPage();
            page.setDefaultUid(MiscUtils.to8DigitHex(fModel.getUID3()));
            String targetname=fModel.getTargetFilename();
            if (targetname!=null) {
                int dotpos=targetname.lastIndexOf('.');
                if (dotpos==-1)
                    dotpos=targetname.length();
                page.setDefaultCaption(targetname.substring(0, dotpos));
            }
            IFile result=createResource(AIF_TEMPLATE_FILENAME, page);
	        if (result==null)
	            return ;
	        addAIFFile(result.getLocation());
        }        
    }
    
    protected void removeClicked()
    {
        TreeItem type=getSelectionType();
        int pos=getSelectionPos();
        if (pos==-1)
            return;
        try {
	        if (type==fResourcesRoot) {
	            if (!MessageDialog.openQuestion(getSection().getShell(),
	                    SymbdevPlugin.MESSAGE_TITLE, "Are you sure that you " +
	                    	"want to remove the reference to this file (the file " +
	                    	"itself won't be removed)"))
	                return;
	            fModel.removeResource(pos);
	        } else if (type==fSystemResourcesRoot) {
	            if (!MessageDialog.openQuestion(getSection().getShell(),
	                    SymbdevPlugin.MESSAGE_TITLE, "Are you sure that you " +
	                    	"want to remove the reference to this file (the file " +
	                    	"itself won't be removed)"))
	                return;
	            fModel.removeSystemResource(pos);
	        } else if (type==fAIFRoot && fModel.getAIFDeclaration()!=null) {
	            if (!MessageDialog.openQuestion(getSection().getShell(),
	                    SymbdevPlugin.MESSAGE_TITLE, "Are you sure that you " +
	                    	"want to remove the AIF definition (the files " +
	                    	"listed won't be removed)"))
	                return;
	            fModel.removeAIFDeclaration();
	        }
        }
        catch (CoreException e) {
            SymbdevPlugin.showError(e, "Error while removing resource",
                    getSection().getShell());
        }
    }

    void resourcesChanged(boolean system)
    {
        if (fItemsTree.isDisposed())
            return;

        TreeItem root=(system?fSystemResourcesRoot:fResourcesRoot);
        TreeItem[] tab=root.getItems();
        for (int i=0; i<tab.length; i++)
            tab[i].dispose();
        MMPFileReference[] resources=(system?fModel.getSystemResources():fModel.getResources());
        for (int i=0; i<resources.length; i++)
        {
            TreeItem ti=new TreeItem(root, SWT.NONE);
            ti.setText(resources[i].getFileStringType(fSDK.epocRoot, 
                    fCurrentDir.toString()).getStringName());
            ti.setImage(SymbdevImages.DESC_RESOURCE_ICON.createImage());
        }
        root.setExpanded(true);
        selectionChanged();
    }
    
    void aifChanged()
    {
        if (fAIFRoot.isDisposed())
            return;
        IAIFDeclaration aif=fModel.getAIFDeclaration();
        if (aif==null)
            fAIFRoot.setText("Application Information File (AIF): none");
        	else fAIFRoot.setText("Application Information File (AIF): "+aif.getTargetFilename());
        selectionChanged();
    }
    
    public void dispose() {
        fModel.removeChangeListener(IMMPModel.CHANGE_RESOURCES, fResourceListener);
        fModel.removeChangeListener(IMMPModel.CHANGE_SYSTEM_RESOURCES, fSystemResourceListener);
        fModel.removeChangeListener(IMMPModel.CHANGE_AIF, fAIFListener);
        super.dispose();
    }
    
    IMMPModel fModel;
    TreeItem fResourcesRoot;
    TreeItem fSystemResourcesRoot;
    TreeItem fAIFRoot;
    TreeItem fMBMRoot;
    Listener fResourceListener;
    Listener fSystemResourceListener;
    Listener fAIFListener;
    
    Button fAdd, fRemove, fCreate;    
    Tree fItemsTree;
    
    SymbianSDKEntry fSDK;
    IPath fCurrentDir;
    IProject fProject;
    Listener fSelectionListener;
}
