/**
 * $Revision$
 * $Date$
 *
 * Copyright 2003-2007 Jive Software.
 *
 * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jivesoftware.smackx.bookmark;

import org.jivesoftware.smackx.packet.PrivateData;
import org.jivesoftware.smackx.provider.PrivateDataProvider;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Bookmarks is used for storing and retrieving URLS and Conference rooms.
 * Bookmark Storage (JEP-0048) defined a protocol for the storage of bookmarks to conference rooms and other entities
 * in a Jabber user's account.
 * See the following code sample for saving Bookmarks:
 * <p/>
 * <pre>
 * Connection con = new XMPPConnection("jabber.org");
 * con.login("john", "doe");
 * Bookmarks bookmarks = new Bookmarks();
 * <p/>
 * // Bookmark a URL
 * BookmarkedURL url = new BookmarkedURL();
 * url.setName("Google");
 * url.setURL("http://www.jivesoftware.com");
 * bookmarks.addURL(url);
 * // Bookmark a Conference room.
 * BookmarkedConference conference = new BookmarkedConference();
 * conference.setName("My Favorite Room");
 * conference.setAutoJoin("true");
 * conference.setJID("dev@conference.jivesoftware.com");
 * bookmarks.addConference(conference);
 * // Save Bookmarks using PrivateDataManager.
 * PrivateDataManager manager = new PrivateDataManager(con);
 * manager.setPrivateData(bookmarks);
 * <p/>
 * <p/>
 * LastActivity activity = LastActivity.getLastActivity(con, "xray@jabber.org");
 * </pre>
 *
 * @author Derek DeMoro
 */
public class Bookmarks implements PrivateData {

    private List<BookmarkedURL> bookmarkedURLS;
    private List<BookmarkedConference> bookmarkedConferences;

    /**
     * Required Empty Constructor to use Bookmarks.
     */
    public Bookmarks() {
        bookmarkedURLS = new ArrayList<BookmarkedURL>();
        bookmarkedConferences = new ArrayList<BookmarkedConference>();
    }

    /**
     * Adds a BookmarkedURL.
     *
     * @param bookmarkedURL the bookmarked bookmarkedURL.
     */
    public void addBookmarkedURL(BookmarkedURL bookmarkedURL) {
        bookmarkedURLS.add(bookmarkedURL);
    }

    /**
     * Removes a bookmarked bookmarkedURL.
     *
     * @param bookmarkedURL the bookmarked bookmarkedURL to remove.
     */
    public void removeBookmarkedURL(BookmarkedURL bookmarkedURL) {
        bookmarkedURLS.remove(bookmarkedURL);
    }

    /**
     * Removes all BookmarkedURLs from user's bookmarks.
     */
    public void clearBookmarkedURLS() {
        bookmarkedURLS.clear();
    }

    /**
     * Add a BookmarkedConference to bookmarks.
     *
     * @param bookmarkedConference the conference to remove.
     */
    public void addBookmarkedConference(BookmarkedConference bookmarkedConference) {
        bookmarkedConferences.add(bookmarkedConference);
    }

    /**
     * Removes a BookmarkedConference.
     *
     * @param bookmarkedConference the BookmarkedConference to remove.
     */
    public void removeBookmarkedConference(BookmarkedConference bookmarkedConference) {
        bookmarkedConferences.remove(bookmarkedConference);
    }

    /**
     * Removes all BookmarkedConferences from Bookmarks.
     */
    public void clearBookmarkedConferences() {
        bookmarkedConferences.clear();
    }

    /**
     * Returns a Collection of all Bookmarked URLs for this user.
     *
     * @return a collection of all Bookmarked URLs.
     */
    public List<BookmarkedURL> getBookmarkedURLS() {
        return bookmarkedURLS;
    }

    /**
     * Returns a Collection of all Bookmarked Conference for this user.
     *
     * @return a collection of all Bookmarked Conferences.
     */
    public List<BookmarkedConference> getBookmarkedConferences() {
        return bookmarkedConferences;
    }


    /**
     * Returns the root element name.
     *
     * @return the element name.
     */
    public String getElementName() {
        return "storage";
    }

    /**
     * Returns the root element XML namespace.
     *
     * @return the namespace.
     */
    public String getNamespace() {
        return "storage:bookmarks";
    }

    /**
     * Returns the XML reppresentation of the PrivateData.
     *
     * @return the private data as XML.
     */
    public String toXML() {
        StringBuilder buf = new StringBuilder();
        buf.append("<storage xmlns=\"storage:bookmarks\">");

        final Iterator<BookmarkedURL> urls = getBookmarkedURLS().iterator();
        while (urls.hasNext()) {
            BookmarkedURL urlStorage = urls.next();
            if(urlStorage.isShared()) {
                continue;
            }
            buf.append("<url name=\"").append(urlStorage.getName()).
                    append("\" url=\"").append(urlStorage.getURL()).append("\"");
            if(urlStorage.isRss()) {
                buf.append(" rss=\"").append(true).append("\"");
            }
            buf.append(" />");
        }

        // Add Conference additions
        final Iterator<BookmarkedConference> conferences = getBookmarkedConferences().iterator();
        while (conferences.hasNext()) {
            BookmarkedConference conference = conferences.next();
            if(conference.isShared()) {
                continue;
            }
            buf.append("<conference ");
            buf.append("name=\"").append(conference.getName()).append("\" ");
            buf.append("autojoin=\"").append(conference.isAutoJoin()).append("\" ");
            buf.append("jid=\"").append(conference.getJid()).append("\" ");
            buf.append(">");

            if (conference.getNickname() != null) {
                buf.append("<nick>").append(conference.getNickname()).append("</nick>");
            }


            if (conference.getPassword() != null) {
                buf.append("<password>").append(conference.getPassword()).append("</password>");
            }
            buf.append("</conference>");
        }


        buf.append("</storage>");
        return buf.toString();
    }

    /**
     * The IQ Provider for BookmarkStorage.
     *
     * @author Derek DeMoro
     */
    public static class Provider implements PrivateDataProvider {

        /**
         * Empty Constructor for PrivateDataProvider.
         */
        public Provider() {
            super();
        }

        public PrivateData parsePrivateData(XmlPullParser parser) throws Exception {
            Bookmarks storage = new Bookmarks();

            boolean done = false;
            while (!done) {
                int eventType = parser.next();
                if (eventType == XmlPullParser.START_TAG && "url".equals(parser.getName())) {
                    final BookmarkedURL urlStorage = getURLStorage(parser);
                    if (urlStorage != null) {
                        storage.addBookmarkedURL(urlStorage);
                    }
                }
                else if (eventType == XmlPullParser.START_TAG &&
                        "conference".equals(parser.getName()))
                {
                    final BookmarkedConference conference = getConferenceStorage(parser);
                    storage.addBookmarkedConference(conference);
                }
                else if (eventType == XmlPullParser.END_TAG && "storage".equals(parser.getName()))
                {
                    done = true;
                }
            }


            return storage;
        }
    }

    private static BookmarkedURL getURLStorage(XmlPullParser parser) throws IOException, XmlPullParserException {
        String name = parser.getAttributeValue("", "name");
        String url = parser.getAttributeValue("", "url");
        String rssString = parser.getAttributeValue("", "rss");
        boolean rss = rssString != null && "true".equals(rssString);

        BookmarkedURL urlStore = new BookmarkedURL(url, name, rss);
        boolean done = false;
        while (!done) {
            int eventType = parser.next();
            if(eventType == XmlPullParser.START_TAG
                        && "shared_bookmark".equals(parser.getName())) {
                    urlStore.setShared(true);
            }
            else if (eventType == XmlPullParser.END_TAG && "url".equals(parser.getName())) {
                done = true;
            }
        }
        return urlStore;
    }

    private static BookmarkedConference getConferenceStorage(XmlPullParser parser) throws Exception {
        String name = parser.getAttributeValue("", "name");
        String autojoin = parser.getAttributeValue("", "autojoin");
        String jid = parser.getAttributeValue("", "jid");

        BookmarkedConference conf = new BookmarkedConference(jid);
        conf.setName(name);
        conf.setAutoJoin(Boolean.valueOf(autojoin).booleanValue());

        // Check for nickname
        boolean done = false;
        while (!done) {
            int eventType = parser.next();
            if (eventType == XmlPullParser.START_TAG && "nick".equals(parser.getName())) {
                conf.setNickname(parser.nextText());
            }
            else if (eventType == XmlPullParser.START_TAG && "password".equals(parser.getName())) {
                conf.setPassword(parser.nextText());
            }
            else if(eventType == XmlPullParser.START_TAG
                        && "shared_bookmark".equals(parser.getName())) {
                    conf.setShared(true);
            }
            else if (eventType == XmlPullParser.END_TAG && "conference".equals(parser.getName())) {
                done = true;
            }
        }


        return conf;
    }
}