package com.quantum.model;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Vector;

import com.quantum.IQuantumConstants;
import com.quantum.Messages;
import com.quantum.model.xml.ModelToXMLConverter;
import com.quantum.sql.metadata.MetaDataXMLInterface;

import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * The collection of database bookmarks that the Quantum plug-in knows about.
 * This collection is loaded by the QuantumPlugin class before any Quantum plugin 
 * extension is invoked.
 * 
 * @author BC
 */
public class BookmarkCollection {
    
    private static BookmarkCollection instance = new BookmarkCollection();
    private List bookmarks = new Vector();
    private boolean changed = false;
    private PropertyChangeSupport support = new PropertyChangeSupport(this);
    
    private BookmarkCollection() {
    }

    /**
     * Singleton accessor
     */
    public static BookmarkCollection getInstance() {
        return BookmarkCollection.instance;
    }
    
    /**
     * Imports the bookmars from a properties file.  This load method is 
     * provided for backwards compatability only; we no longer persist 
     * bookmarks as properties files.
     * @param file
     */
    public void load(File file) throws IOException {
        Properties props = new Properties();
        FileInputStream in = new FileInputStream(file);
        props.load(in);
        in.close();
        fromProperties(true, props);
    }
     
    private void fromProperties(boolean overwrite, Properties props) {
        List newBookmarks = new Vector();
        int i = 0;
        while (true) {
            Bookmark bookmark = new Bookmark();
            String name = props.getProperty(i + ".name"); //$NON-NLS-1$
            if (name == null) {
                break;
            }
            bookmark.setName(name);
            bookmark.setUsername(props.getProperty(i + ".username")); //$NON-NLS-1$
            bookmark.setPassword(props.getProperty(i + ".password")); //$NON-NLS-1$
            bookmark.setConnect(props.getProperty(i + ".connect")); //$NON-NLS-1$
            bookmark.setDriver(props.getProperty(i + ".driver")); //$NON-NLS-1$
            String schema = props.getProperty(i + ".schema"); //$NON-NLS-1$
            if (schema != null) {
                bookmark.addSchema(schema);
            }
            String type = props.getProperty(i + ".type"); //$NON-NLS-1$
            if (type != null) {
                bookmark.setType(type);
            } else {
                bookmark.setType(""); //$NON-NLS-1$
            }
            String driverFile = props.getProperty(i + ".driverLocation"); //$NON-NLS-1$
            if (driverFile != null) {
                bookmark.setDriverFile(driverFile);
            } else {
                bookmark.setDriverFile(""); //$NON-NLS-1$
            }
            System.out.println(bookmark.toString());
            if (!bookmark.isEmpty()) {
                newBookmarks.add(bookmark);
            }
            i++;
        }
        if (overwrite) {
            this.bookmarks = newBookmarks;
        } else {
            this.bookmarks.addAll(newBookmarks);
        }
    }
    /**
     * Finds a Bookmark with the specified name.
     * 
     * @param name
     * @return the bookmark with the specified name, or null if no bookmark can be found
     */
    public Bookmark find(String name){
        Bookmark result = null;
        if (name != null) {
            for (Iterator i = this.bookmarks.iterator(); result == null && i.hasNext(); ) {
                Bookmark temp = (Bookmark) i.next();
                if (name.equals(temp.getName())) {
                    result = temp;
                }
            }
        }
        return result;
    }

    /**
     * Exports a Bookmark data to an XMLDocument Element
     * The complementary function is importXML()
     * @param root  The Element to fill up with the bookmark info
     */
    public void exportXML(Element root) {
        System.out.println("Bookmarks: Saving to Element"); //$NON-NLS-1$
        Element bookmarkRoot = MetaDataXMLInterface.createElementText(root,"bookmarks", ""); //$NON-NLS-1$ //$NON-NLS-2$
        for (int i = 0; i < bookmarks.size(); i++) {
            Bookmark b = (Bookmark) bookmarks.get(i);
            ModelToXMLConverter.getInstance().convert(bookmarkRoot, b);
        }
    }

    /**
     * Imports a Bookmark data from an XMLDocument Element
     * The complementary function is exportXML()
     * @param root  The Element from which to load
     */
    public void importXML(Element root) {
        this.changed = true;
        System.out.println("Bookmarks: Loading from Element"); //$NON-NLS-1$
        Vector newBookmarks = new Vector();
        NodeList nodes = root.getElementsByTagName("bookmark"); //$NON-NLS-1$
        for (int i = 0; i < nodes.getLength(); i++) {
            Bookmark bookmark = new Bookmark();
            Element column = (Element) nodes.item(i);
            
            String name = MetaDataXMLInterface.getElementText(column,"name"); //$NON-NLS-1$
            if (name == null) break;
            bookmark.setName(name);
            
            MetaDataXMLInterface.getElementText(column,"name"); //$NON-NLS-1$
            bookmark.setUsername(MetaDataXMLInterface.getElementText(column,"username")); //$NON-NLS-1$
            bookmark.setPassword(MetaDataXMLInterface.getElementText(column,"password")); //$NON-NLS-1$
            bookmark.setPromptForPassword(Boolean.TRUE.toString().equalsIgnoreCase(
                MetaDataXMLInterface.getElementText(column,"prompt"))); //$NON-NLS-1$
            bookmark.setConnect(MetaDataXMLInterface.getElementText(column,"connect")); //$NON-NLS-1$
			bookmark.setAutoCommit(Boolean.TRUE.toString().equalsIgnoreCase(
				MetaDataXMLInterface.getElementText(column,"autoCommit", "True"))); //$NON-NLS-1$
			bookmark.setAutoCommitPreference(MetaDataXMLInterface.getElementText(column,"autoCommitPreference", IQuantumConstants.autoCommitTrue)); //$NON-NLS-1$
            bookmark.setDriver(MetaDataXMLInterface.getElementText(column,"driver")); //$NON-NLS-1$
            bookmark.addSchema(MetaDataXMLInterface.getElementText(column,"schema")); //$NON-NLS-1$
            bookmark.setType(MetaDataXMLInterface.getElementText(column,"type")); //$NON-NLS-1$
            bookmark.setDriverFile(MetaDataXMLInterface.getElementText(column,"driverLocation")); //$NON-NLS-1$
            NodeList children = column.getElementsByTagName(Messages.getString("ExportXMLAction.OtherSchemas"));
            if (children.getLength() > 0) {
                importSchemas((Element) children.item(0), bookmark);
            }
            System.out.println(bookmark.toString());
            if (!bookmark.isEmpty()) {
                newBookmarks.addElement(bookmark);
            }
            importQuickList(bookmark, column);
            importQueryList(bookmark, column);
        }
        this.bookmarks.addAll(newBookmarks);
        this.support.firePropertyChange("bookmarks", null, null);
    }

    private void importSchemas(Element otherSchemas, Bookmark bookmark) {
        Vector vector = MetaDataXMLInterface.getVectorText(otherSchemas, Messages.getString("ExportXMLAction.SchemaName"));
        List list = new ArrayList();
        for (Iterator i = vector.iterator(); i.hasNext();) {
            String schemaName = (String) i.next();
            list.add(new Schema(schemaName));
        }
        bookmark.setSchemas((Schema[]) list.toArray(new Schema[list.size()]));
    }

    private void importQuickList(Bookmark bookmark, Element bookmarkElement) {
        NodeList quickList = bookmarkElement.getElementsByTagName("quickList");
        for (int j = 0,
            length = (quickList == null) ? 0 : quickList.getLength();
            j < length;
            j++) {
            
            Element element = (Element) quickList.item(j);
            NodeList childNodes = element.getChildNodes();
                
            for (int k = 0,
                length2 = (childNodes == null) ? 0 : childNodes.getLength();
                k < length2;
                k++) {
                if (Node.ELEMENT_NODE == childNodes.item(k).getNodeType()) {
                    Element entity = (Element) childNodes.item(k);
                    bookmark.addQuickListEntry(entity.getTagName(), 
                        entity.getAttribute("schema"), entity.getAttribute("name"));
                }
            }
        }
    }
    
    private void importQueryList(Bookmark bookmark, Element bookmarkElement) {
        NodeList queryList = bookmarkElement.getElementsByTagName("queryList");
        for (int i = 0,
            length = (queryList == null) ? 0 : queryList.getLength();
            i < length;
            i++) {
            
            Element element = (Element) queryList.item(i);
            NodeList childNodes = element.getElementsByTagName("query");
                
            for (int k = 0,
                length2 = (childNodes == null) ? 0 : childNodes.getLength();
                k < length2;
                k++) {

                Element query = (Element) childNodes.item(k);
                bookmark.addQuery(MetaDataXMLInterface.getElementText(query,"queryString"));
        
            }
        }
    }
    
    public void addBookmark(Bookmark b) {
        this.changed = true;
        if (!bookmarks.contains(b)) {
            Bookmark[] original = getBookmarks();
            bookmarks.add(b);
            this.support.firePropertyChange("bookmarks", original, getBookmarks());
        }
    }
    public void removeBookmark(Bookmark b) {
        this.changed = true;
        if (bookmarks.contains(b)) {
            Bookmark[] original = getBookmarks();
            bookmarks.remove(b);
            this.support.firePropertyChange("bookmarks", original, getBookmarks());
        }
    }
    
    public Bookmark[] getBookmarks() {
        return (Bookmark[]) this.bookmarks.toArray(new Bookmark[this.bookmarks.size()]);
    }
    /**
     * @return
     */
    public boolean isAnythingChanged() {
        boolean anythingChanged = this.changed;
        for (Iterator i = this.bookmarks.iterator(); !anythingChanged && i.hasNext();) {
            Bookmark bookmark = (Bookmark) i.next();
            anythingChanged |= bookmark.isChanged();
        }
        return anythingChanged;
    }
    
    public boolean isChanged() {
        return this.changed;
    }

    /**
     * @param b
     */
    public void setChanged(boolean changed) {
        this.changed = changed;
    }

    /**
     * @param listener
     */
    public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
        this.support.addPropertyChangeListener(listener);
    }

    /**
     * @param listener
     */
    public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
        this.support.removePropertyChangeListener(listener);
    }

	/**
	 * @param string
	 * @return
	 */
	public String getCopyName(String name) {
		
		String copyName = Messages.getString("BookmarkView.CopyOf") + name;
		int i = 1;
		while (find(copyName) != null)
		{
			copyName = Messages.getString("BookmarkView.CopyOf") + name + "(" + String.valueOf(i) + ")";
			i++;
		}
		
		return copyName;
	}


}