/*
 * AddressBookimpl.java
 * class implementing the AddressBook interface
 * in AddressBook API
 */

import java.util.Hashtable;
import java.util.Enumeration;
import java.io.*;
import addressbooklib.*;
import addressbooklib.Application;
import addressbooklib.Errors;
import com.ms.com.ComFailException;
import com.ms.com.IUnknown;
import com.ms.com.Variant;

/**
 * Implementation of AddressBook dual interface
 * @Author Ken Bandes
 */
public class AddressBookimpl 
    implements AddressBook, Serializable
{
    private static final String CLSID = 
        "4F9DFA92-32EF-11D1-B5AC-9E4A44000000";

    /**
     * Constructor
     * @param parent the containing AddressBooksimpl object
     * @param file the File containing (or to contain) this book
     */
    public AddressBookimpl(
                AddressBooksimpl parent,
                File file)
    {
        this.parent = parent;
        this.file = file;
    }

    /**
     * implementation of addressbook.AddressBook.getApplication
     * @return the Application object for this API instance
     */
    public Application getApplication()
    {
        return parent.getApplication();
    }

    /**
     * implementation of addressbook.AddressBook.getParent
     * @return the parent AddressBooks collection
     */
    public AddressBooks getParent()
    {
        return (AddressBooks) parent;
    }

    /**
     * implementation of addressbook.AddressBook.getFullName
     * @return the file name, with fully-qualified path
     */
    public String getFullName()
    {
        return file.getAbsolutePath();
    }

    /**
     * implementation of addressbook.AddressBook.getName
     * @return the filename, sans path
     */
    public String getName()
    {
        return file.getName();
    }

    /**
     * implementation of addressbook.AddressBook.getPath
     * @return the path to this file, without the file name
     */
    public String getPath()
    {
        return getFullName().substring(
                    0, 
                    getFullName().lastIndexOf(getName()));
    }

    /**
     * implementation of addressbook.AddressBook.getSaved
     * @return boolean to indicate if file saved since last change
     */
    public boolean getSaved()
    {
        return saved;
    }

    /**
     * implementation of addressbook.AddressBook.Close<br>
     * remove this AddressBook from the (parent) collection
     */
    public void Close()
    {
        parent.remove(this);
    }

    /**
     * implementation of addressbook.AddressBook.Save<br>
     * save changes to the file (using serialization)
     */
    public void Save()
    {
        try
        {
            FileOutputStream fos = new FileOutputStream(file);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(this);
            oos.flush();
            oos.close();
        }
        catch(IOException ex)
        {
            throw new ComFailException(Errors.E_SAVEFAILED,
                "Unable to save to " + getFullName());
        }
    }

    /**
     * implementation of addressbook.AddressBook.getCount<br>
     * @return the number of entries in this AddressBook
     */
    public int getCount()
    {
        return entries.size();
    }

    /**
     * implementation of addressbook.AddressBook.get_NewEnum
     * @return the IUnknown pointer to an object implementing 
     * IEnumVARIANT
     */
    public IUnknown get_NewEnum()
    {
        return (IUnknown) getAutoEnum();
    }

    /**
     * implementation of addressbook.AddressBook.Add
     * @param Name the name for a new Address entry
     * @return the new Address entry
     */
    public Address Add(String Name)
    {
        Addressimpl entry = new Addressimpl(this);
        entry.setName(Name);
        entries.put(Name, entry);
        setUnsaved();
        return (Address) entry;
    }

    /**
     * implementation of addressbook.AddressBook.Item<br>
     * retrieve an Address entry by name
     * @param Name the name of the desired entry
     * @return the Address entry for the specified name
     */
    public Address Item(String Name)
    {
        Addressimpl entry = (Addressimpl) entries.get(Name);
        if(entry == null)
            throw new ComFailException(
                        Errors.E_ITEMNOTFOUND, 
                        "Address entry " + Name + " Not Found");

        return (Address) entry;
    }

    /**
     * implementation of addressbook.AddressBook.Remove<br>
     * remove an entry from the AddressBook
     * @param Name the name of the entry to remove
     */
    public void Remove(String Name)
    {
        entries.remove(Name);
        setUnsaved();
    }

    /**
     * implementation of addressbook.AddressBook.getEnum
     * @return a DIEnum interface to provide a simple enumeration
     */
    public DIEnum getEnum()
    {
        return (DIEnum) getAutoEnum();
    }

    // package-accessible methods

    /**
     * set the parent reference<br>
     * for deserialized object
     * @param parent the containing AddressBooks collection
     */
    void setParent(AddressBooksimpl parent)
    {
        this.parent = parent;
    }

    /**
     * set the file specification<br>
     * for deserialized object
     * @param file the file for this book
     */
    void setFile(File file)
    {
        this.file = file;
    }

    /**
     * mark book as changed since last save
     */
    void setUnsaved()
    {
        saved = false;
    }

    // private methods

    // override serialization to mark object as clean (saved)
    private void writeObject(ObjectOutputStream out)
        throws IOException
    {
        out.defaultWriteObject();
        saved = true;
    }

    // get a COM enumeration object for this collection
    private AutoEnum getAutoEnum()
    {
        /* use an anonymous class to implement the Enumerable
         * interface required by AutoEnum's constructor
         */
        return new AutoEnum(new Enumerable() {
            // get an Enumeration on the collection
            public Enumeration elements()
            {
                return entries.elements();
            }
        });
    }

    // private data
    private transient AddressBooksimpl parent;
    private transient File file;
    private transient boolean saved = true;
    private Hashtable entries = new Hashtable();
}
