package net.sourceforge.phpeclipse.resourcesview;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.SAXParserFactory;

import net.sourceforge.phpeclipse.LoadPathEntry;
import net.sourceforge.phpeclipse.PHPeclipsePlugin;

import org.eclipse.core.resources.ICommand;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IProjectNature;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

public class PHPProject implements IProjectNature, PHPElement {
  protected IProject fProject;
 // protected IndexFileReader fIndexManager;
  protected List fLoadPathEntries;
  protected boolean fScratched;

  public PHPProject() {
  }

  public void addLoadPathEntry(IProject anotherPHPProject) {
    fScratched = true;

    LoadPathEntry newEntry = new LoadPathEntry(anotherPHPProject);
    getLoadPathEntries().add(newEntry);
  }

  public void configure() throws CoreException {
    //	get project description and then the associated build commands 
    IProjectDescription desc = fProject.getDescription();
    ICommand[] commands = desc.getBuildSpec();

    // determine if builder already associated
    boolean found = false;
    for (int i = 0; i < commands.length; ++i) {
      if (commands[i].getBuilderName().equals(PHPeclipsePlugin.BUILDER_PARSER_ID)) {
        found = true;
        break;
      }
    }

    // add builder if not already in project
    if (!found) {
      ICommand command = desc.newCommand();
      command.setBuilderName(PHPeclipsePlugin.BUILDER_PARSER_ID);
      ICommand[] newCommands = new ICommand[commands.length + 1];

      // Add it before other builders. 
      System.arraycopy(commands, 0, newCommands, 1, commands.length);
      newCommands[0] = command;
      desc.setBuildSpec(newCommands);
      fProject.setDescription(desc, null);
    }
  }

  public void deconfigure() throws CoreException {
  }

  public List getLoadPathEntries() {
    if (fLoadPathEntries == null) {
      loadLoadPathEntries();
    }

    return fLoadPathEntries;
  }

  protected ContentHandler getLoadPathEntriesContentHandler() {
    return new ContentHandler() {
      public void characters(char[] arg0, int arg1, int arg2) throws SAXException {
      }

      public void endDocument() throws SAXException {
      }

      public void endElement(String arg0, String arg1, String arg2) throws SAXException {
      }

      public void endPrefixMapping(String arg0) throws SAXException {
      }

      public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {
      }

      public void processingInstruction(String arg0, String arg1) throws SAXException {
      }

      public void setDocumentLocator(Locator arg0) {
      }

      public void skippedEntity(String arg0) throws SAXException {
      }

      public void startDocument() throws SAXException {
      }

      public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
        if ("pathentry".equals(qName))
          if ("project".equals(atts.getValue("type"))) {
            IPath referencedProjectPath = new Path(atts.getValue("path"));
            IProject referencedProject = getProject(referencedProjectPath.lastSegment());
            fLoadPathEntries.add(new LoadPathEntry(referencedProject));
          }
      }

      public void startPrefixMapping(String arg0, String arg1) throws SAXException {
      }
    };
  }

  protected IFile getLoadPathEntriesFile() {
    return fProject.getFile(".loadpath");
  }

  protected String getLoadPathXML() {
    StringBuffer buffer = new StringBuffer();
    buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><loadpath>");

    Iterator pathEntriesIterator = fLoadPathEntries.iterator();

    while (pathEntriesIterator.hasNext()) {
      LoadPathEntry entry = (LoadPathEntry) pathEntriesIterator.next();
      buffer.append(entry.toXML());
    }

    buffer.append("</loadpath>");
    return buffer.toString();
  }

  public IProject getProject() {
    return fProject;
  }

  protected IProject getProject(String name) {
    return PHPeclipsePlugin.getWorkspace().getRoot().getProject(name);
  }

  public List getReferencedProjects() {
    List referencedProjects = new ArrayList();

    Iterator iterator = getLoadPathEntries().iterator();
    while (iterator.hasNext()) {
      LoadPathEntry pathEntry = (LoadPathEntry) iterator.next();
      if (pathEntry.getType() == LoadPathEntry.TYPE_PROJECT)
        referencedProjects.add(pathEntry.getProject());
    }

    return referencedProjects;
  }

  public IResource getUnderlyingResource() {
    return fProject;
  }

  protected void loadLoadPathEntries() {
    fLoadPathEntries = new ArrayList();

    IFile loadPathsFile = getLoadPathEntriesFile();

    XMLReader reader = null;
    try {
      reader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
      reader.setContentHandler(getLoadPathEntriesContentHandler());
      reader.parse(new InputSource(loadPathsFile.getContents()));
    } catch (Exception e) {
      //the file is nonextant or unreadable
    }
  }

  public void removeLoadPathEntry(IProject anotherPHPProject) {
    Iterator entries = getLoadPathEntries().iterator();
    while (entries.hasNext()) {
      LoadPathEntry entry = (LoadPathEntry) entries.next();
      if (entry.getType() == LoadPathEntry.TYPE_PROJECT && entry.getProject().getName().equals(anotherPHPProject.getName())) {
        getLoadPathEntries().remove(entry);
        fScratched = true;
        break;
      }
    }
  }

  public void save() throws CoreException {
    if (fScratched) {
      InputStream xmlPath = new ByteArrayInputStream(getLoadPathXML().getBytes());
      IFile loadPathsFile = getLoadPathEntriesFile();
      if (!loadPathsFile.exists())
        loadPathsFile.create(xmlPath, true, null);
      else
        loadPathsFile.setContents(xmlPath, true, false, null);

      fScratched = false;
    }
  }

  public void setProject(IProject aProject) {
    fProject = aProject;
  }

}