
package cz.karry.dop.nbmodule.project;

import cz.karry.dop.nbmodule.DopSharedConstants;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.IOException;
import java.net.URL;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectInformation;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.spi.project.AuxiliaryConfiguration;
import org.netbeans.spi.project.SubprojectProvider;
import org.netbeans.spi.project.support.ant.AntProjectEvent;
import org.netbeans.spi.project.support.ant.AntProjectHelper;
import org.netbeans.spi.project.support.ant.AntProjectListener;
import org.netbeans.spi.project.support.ant.GeneratedFilesHelper;
import org.netbeans.spi.project.support.ant.ProjectXmlSavedHook;
import org.netbeans.spi.project.support.ant.PropertyEvaluator;
import org.netbeans.spi.project.support.ant.PropertyUtils;
import org.netbeans.spi.project.support.ant.ReferenceHelper;
import org.netbeans.spi.project.ui.ProjectOpenedHook;
import org.openide.ErrorManager;
import org.openide.filesystems.FileObject;
import org.openide.util.Lookup;
import org.openide.util.Mutex;
import org.openide.util.Utilities;
import org.openide.util.lookup.Lookups;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;


import java.io.*;
import javax.swing.*;
import org.netbeans.spi.project.ui.PrivilegedTemplates;
import org.netbeans.spi.project.ui.RecommendedTemplates;

public class DopProject implements Project, AntProjectListener {

     public static final String SRC_DIR = "src.dir";
    
    private Icon PROJECT_ICON;
    private final AntProjectHelper myHelper;
    private PropertyEvaluator myEvaluator;
    private final ReferenceHelper myRefHelper;
    private GeneratedFilesHelper myGenFilesHelper;
    private Lookup myLookup;
    
    DopProject( AntProjectHelper helper ) {
        URL resources = getClass().getResource("/cz/karry/dop/nbmodule/microprocessor_small.png");
        //String file = resources.getFile();
        PROJECT_ICON = new javax.swing.ImageIcon( resources );
        

        myHelper = helper;
        AuxiliaryConfiguration configuration = 
            helper.createAuxiliaryConfiguration();
        myRefHelper = new ReferenceHelper(helper, configuration, getEvaluator());
        myGenFilesHelper = new GeneratedFilesHelper( helper );
        helper.addAntProjectListener(this);
        initLookup( configuration );

    }

    /* (non-Javadoc)
     * @see org.netbeans.api.project.Project#getLookup()
     */
    public Lookup getLookup() {
        return myLookup;
    }

    /* (non-Javadoc)
     * @see org.netbeans.api.project.Project#getProjectDirectory()
     */
    public FileObject getProjectDirectory() {
        return getHelper().getProjectDirectory();
    }

    /* (non-Javadoc)
     * @see org.netbeans.spi.project.support.ant.AntProjectListener#configurationXmlChanged(org.netbeans.spi.project.support.ant.AntProjectEvent)
     */
    public void configurationXmlChanged( AntProjectEvent event ) {
        /*
         *  The code below is standart and copied f.e. from MakeProject
         */
        if (event.getPath().equals( AntProjectHelper.PROJECT_XML_PATH ) ) {
            // Could be various kinds of changes, but name & displayName might have changed.
            Info info = (Info)getLookup().lookup( ProjectInformation.class );
            info.firePropertyChange( ProjectInformation.PROP_NAME );
            info.firePropertyChange( ProjectInformation.PROP_DISPLAY_NAME );
        }

    }

    /* (non-Javadoc)
     * @see org.netbeans.spi.project.support.ant.AntProjectListener#propertiesChanged(org.netbeans.spi.project.support.ant.AntProjectEvent)
     */
    public void propertiesChanged( AntProjectEvent arg0 ) {
        // We are interested only to listen to changes in sources.
        /*
         * Also copied from  MakeProject
         */
        //  currently ignored (probably better to listen to evaluator() if you need to)
    }
    
    /*
     * Copied from MakeProject.
     */
    public String getName() {
        return ProjectManager.mutex().readAccess(
                new Mutex.Action<String>() 
                {

                    public String run() {
                        Element data = getHelper().getPrimaryConfigurationData(true);
                        NodeList nl = data.getElementsByTagNameNS(
                                DopProjectType.PROJECT_CONFIGURATION_NAMESPACE, DopSharedConstants.PROJECT_NAME_ELEMENT);
                        if (nl.getLength() == 1) {
                            nl = nl.item(0).getChildNodes();
                            if (nl.getLength() == 1
                                    && nl.item(0).getNodeType() == Node.TEXT_NODE)
                            {
                                return ((Text) nl.item(0)).getNodeValue();
                            }
                        }
                        return DopSharedConstants.DEFAULT_PROJECT_NAME;                                           // NOI18N
                    }
                });
    }
    
    /*
     * Copied from MakeProject.
     */
    public void setName( final String name ) {
        ProjectManager.mutex().writeAccess(new Mutex.Action<Object>() {

            public Object run() {
                Element data = getHelper().getPrimaryConfigurationData(true);
                NodeList nl = data.getElementsByTagNameNS(
                        DopProjectType.PROJECT_CONFIGURATION_NAMESPACE, DopSharedConstants.DEFAULT_PROJECT_NAME); 
                Element nameEl;
                if (nl.getLength() == 1) {
                    nameEl = (Element) nl.item(0);
                    NodeList deadKids = nameEl.getChildNodes();
                    while (deadKids.getLength() > 0) {
                        nameEl.removeChild(deadKids.item(0));
                    }
                }
                else {
                    nameEl = data.getOwnerDocument().createElementNS(
                            DopProjectType.PROJECT_CONFIGURATION_NAMESPACE,
                            DopSharedConstants.DEFAULT_PROJECT_NAME); 
                    data.insertBefore(nameEl, /* OK if null */data
                            .getChildNodes().item(0));
                }
                nameEl
                        .appendChild(data.getOwnerDocument().createTextNode(
                                name));
                getHelper().putPrimaryConfigurationData(data, true);
                return null;
            }
        });
    }
    
    public AntProjectHelper getHelper() {
        return myHelper;
    }
    
    public PropertyEvaluator getEvaluator() {
        if ( myEvaluator == null ) {
            myEvaluator = getHelper().getStandardPropertyEvaluator();
        }
        return myEvaluator;
    }



    

    public ReferenceHelper getRefHelper() {
        return myRefHelper;
    }
    
    private final class Info implements ProjectInformation {

        /* (non-Javadoc)
         * @see org.netbeans.api.project.ProjectInformation#addPropertyChangeListener(java.beans.PropertyChangeListener)
         */
        public void addPropertyChangeListener( PropertyChangeListener  listener  ) {
            mySupport.addPropertyChangeListener( listener );
        }

        /* (non-Javadoc)
         * @see org.netbeans.api.project.ProjectInformation#getDisplayName()
         */
        public String getDisplayName() {
            return PropertyUtils.getUsablePropertyName(getName());
        }

        /* (non-Javadoc)
         * @see org.netbeans.api.project.ProjectInformation#getIcon()
         */
        public Icon getIcon() {
            return PROJECT_ICON;
        }

        /* (non-Javadoc)
         * @see org.netbeans.api.project.ProjectInformation#getName()
         */
        public String getName() {
            return DopProject.this.getName();
        }

        /* (non-Javadoc)
         * @see org.netbeans.api.project.ProjectInformation#getProject()
         */
        public Project getProject() {
            return DopProject.this;
        }

        /* (non-Javadoc)
         * @see org.netbeans.api.project.ProjectInformation#removePropertyChangeListener(java.beans.PropertyChangeListener)
         */
        public void removePropertyChangeListener( PropertyChangeListener listener ){
            mySupport.removePropertyChangeListener(listener);
        }
        
        void firePropertyChange(String prop) {
            mySupport.firePropertyChange( prop , null, null );
        }
        
        private final PropertyChangeSupport mySupport = 
            new PropertyChangeSupport(this);
 
    }
    
    private final class DopXmlSavedHook extends ProjectXmlSavedHook {
        
        protected void projectXmlSaved() {
        /*
            It seems we don't have "build" scripts here in this project.
            So I commented out this code at least for now. 
            
            genFilesHelper.refreshBuildScript(
                GeneratedFilesHelper.BUILD_IMPL_XML_PATH,
                MakeProject.class.getResource("resources/build-impl.xsl"),
                false);
            genFilesHelper.refreshBuildScript(
                GeneratedFilesHelper.BUILD_XML_PATH,
                MakeProject.class.getResource("resources/build.xsl"),
                false);
        */
        }
    }

    
    private void initLookup( AuxiliaryConfiguration configuration ) {        
        SubprojectProvider provider = getRefHelper().createSubprojectProvider();
        DopSources dopSources = new DopSources(getHelper(), getEvaluator());
        myLookup = Lookups.fixed(new Object[] {
            new DopPrivTempl(),
            //new DopRecTempl(),            
            new DopLogicalViewProvider( this , provider ),
            new Info(),
            new DopXmlSavedHook(),
            getHelper(),
            getHelper().createCacheDirectoryProvider(),
            getEvaluator(),
            dopSources,
            configuration
        });
    }


  private static final class DopPrivTempl implements PrivilegedTemplates {
    private static final String[] PRIV_TEMPL = new String[] {
        "Templates/Microprocessor/DopMicroassemblerTemplate.mas",
        "Templates/Other/Folder"
    };
     
    public String[] getPrivilegedTemplates() {
      return PRIV_TEMPL;
    }
    
  }
  
  /*
  private static final class DopRecTempl implements RecommendedTemplates {
    private static final String[] REC_TYPES = new String[] {"dop-files"};
     
    public String[] getRecommendedTypes() {
      return REC_TYPES;
    }

  }
   */
}
