/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.chemistry.opencmis.client.bindings.spi.atompub;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import org.apache.chemistry.opencmis.client.bindings.spi.BindingSession;
import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomBase;
import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomElement;
import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomEntry;
import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomFeed;
import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomLink;
import org.apache.chemistry.opencmis.client.bindings.spi.http.Response;
import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
import org.apache.chemistry.opencmis.commons.data.ObjectData;
import org.apache.chemistry.opencmis.commons.data.ObjectInFolderContainer;
import org.apache.chemistry.opencmis.commons.data.ObjectInFolderData;
import org.apache.chemistry.opencmis.commons.data.ObjectInFolderList;
import org.apache.chemistry.opencmis.commons.data.ObjectList;
import org.apache.chemistry.opencmis.commons.data.ObjectParentData;
import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
import org.apache.chemistry.opencmis.commons.impl.Constants;
import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderContainerImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderDataImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderListImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectListImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectParentDataImpl;
import org.apache.chemistry.opencmis.commons.spi.NavigationService;

/**
 * Navigation Service AtomPub client.
 */
public class NavigationServiceImpl extends AbstractAtomPubService implements NavigationService {

    /**
     * Constructor.
     */
    public NavigationServiceImpl(BindingSession session) {
        setSession(session);
    }

    public ObjectInFolderList getChildren(String repositoryId, String folderId, String filter, String orderBy,
            Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
            Boolean includePathSegment, BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) {
        ObjectInFolderListImpl result = new ObjectInFolderListImpl();

        // find the link
        String link = loadLink(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);

        if (link == null) {
            throwLinkException(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
        }

        UrlBuilder url = new UrlBuilder(link);
        url.addParameter(Constants.PARAM_FILTER, filter);
        url.addParameter(Constants.PARAM_ORDER_BY, orderBy);
        url.addParameter(Constants.PARAM_ALLOWABLE_ACTIONS, includeAllowableActions);
        url.addParameter(Constants.PARAM_RELATIONSHIPS, includeRelationships);
        url.addParameter(Constants.PARAM_RENDITION_FILTER, renditionFilter);
        url.addParameter(Constants.PARAM_PATH_SEGMENT, includePathSegment);
        url.addParameter(Constants.PARAM_MAX_ITEMS, maxItems);
        url.addParameter(Constants.PARAM_SKIP_COUNT, skipCount);

        // read and parse
        Response resp = read(url);
        AtomFeed feed = parse(resp.getStream(), AtomFeed.class);

        // handle top level
        for (AtomElement element : feed.getElements()) {
            if (element.getObject() instanceof AtomLink) {
                if (isNextLink(element)) {
                    result.setHasMoreItems(Boolean.TRUE);
                }
            } else if (isInt(NAME_NUM_ITEMS, element)) {
                result.setNumItems((BigInteger) element.getObject());
            }
        }

        // get the children
        if (!feed.getEntries().isEmpty()) {
            result.setObjects(new ArrayList<ObjectInFolderData>(feed.getEntries().size()));

            for (AtomEntry entry : feed.getEntries()) {
                ObjectInFolderDataImpl child = null;
                String pathSegment = null;

                lockLinks();
                try {
                    // clean up cache
                    removeLinks(repositoryId, entry.getId());

                    // walk through the entry
                    for (AtomElement element : entry.getElements()) {
                        if (element.getObject() instanceof AtomLink) {
                            addLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
                        } else if (isStr(NAME_PATH_SEGMENT, element)) {
                            pathSegment = (String) element.getObject();
                        } else if (element.getObject() instanceof ObjectData) {
                            child = new ObjectInFolderDataImpl();
                            child.setObject((ObjectData) element.getObject());
                        }
                    }
                } finally {
                    unlockLinks();
                }

                if (child != null) {
                    child.setPathSegment(pathSegment);
                    result.getObjects().add(child);
                }
            }
        }

        return result;
    }

    public List<ObjectInFolderContainer> getDescendants(String repositoryId, String folderId, BigInteger depth,
            String filter, Boolean includeAllowableActions, IncludeRelationships includeRelationships,
            String renditionFilter, Boolean includePathSegment, ExtensionsData extension) {
        List<ObjectInFolderContainer> result = new ArrayList<ObjectInFolderContainer>();

        // find the link
        String link = loadLink(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_DESCENDANTS);

        if (link == null) {
            throwLinkException(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_DESCENDANTS);
        }

        UrlBuilder url = new UrlBuilder(link);
        url.addParameter(Constants.PARAM_DEPTH, depth);
        url.addParameter(Constants.PARAM_FILTER, filter);
        url.addParameter(Constants.PARAM_ALLOWABLE_ACTIONS, includeAllowableActions);
        url.addParameter(Constants.PARAM_RELATIONSHIPS, includeRelationships);
        url.addParameter(Constants.PARAM_RENDITION_FILTER, renditionFilter);
        url.addParameter(Constants.PARAM_PATH_SEGMENT, includePathSegment);

        // read and parse
        Response resp = read(url);
        AtomFeed feed = parse(resp.getStream(), AtomFeed.class);

        // process tree
        addDescendantsLevel(repositoryId, feed, result);

        return result;
    }

    public ObjectData getFolderParent(String repositoryId, String folderId, String filter, ExtensionsData extension) {
        ObjectData result = null;

        // find the link
        String link = loadLink(repositoryId, folderId, Constants.REL_UP, Constants.MEDIATYPE_ENTRY);

        if (link == null) {
            throwLinkException(repositoryId, folderId, Constants.REL_UP, Constants.MEDIATYPE_ENTRY);
        }

        UrlBuilder url = new UrlBuilder(link);
        url.addParameter(Constants.PARAM_FILTER, filter);

        // read
        Response resp = read(url);

        AtomBase base = parse(resp.getStream(), AtomBase.class);

        // get the entry
        AtomEntry entry = null;
        if (base instanceof AtomFeed) {
            AtomFeed feed = (AtomFeed) base;
            if (feed.getEntries().isEmpty()) {
                throw new CmisRuntimeException("Parent feed is empty!");
            }
            entry = feed.getEntries().get(0);
        } else if (base instanceof AtomEntry) {
            entry = (AtomEntry) base;
        } else {
            throw new CmisRuntimeException("Unexpected document!");
        }

        lockLinks();
        try {
            // clean up cache
            removeLinks(repositoryId, entry.getId());

            // walk through the entry
            for (AtomElement element : entry.getElements()) {
                if (element.getObject() instanceof AtomLink) {
                    addLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
                } else if (element.getObject() instanceof ObjectData) {
                    result = (ObjectData) element.getObject();
                }
            }
        } finally {
            unlockLinks();
        }

        return result;
    }

    public List<ObjectInFolderContainer> getFolderTree(String repositoryId, String folderId, BigInteger depth,
            String filter, Boolean includeAllowableActions, IncludeRelationships includeRelationships,
            String renditionFilter, Boolean includePathSegment, ExtensionsData extension) {
        List<ObjectInFolderContainer> result = new ArrayList<ObjectInFolderContainer>();

        // find the link
        String link = loadLink(repositoryId, folderId, Constants.REL_FOLDERTREE, Constants.MEDIATYPE_DESCENDANTS);

        if (link == null) {
            throwLinkException(repositoryId, folderId, Constants.REL_FOLDERTREE, Constants.MEDIATYPE_DESCENDANTS);
        }

        UrlBuilder url = new UrlBuilder(link);
        url.addParameter(Constants.PARAM_DEPTH, depth);
        url.addParameter(Constants.PARAM_FILTER, filter);
        url.addParameter(Constants.PARAM_ALLOWABLE_ACTIONS, includeAllowableActions);
        url.addParameter(Constants.PARAM_RELATIONSHIPS, includeRelationships);
        url.addParameter(Constants.PARAM_RENDITION_FILTER, renditionFilter);
        url.addParameter(Constants.PARAM_PATH_SEGMENT, includePathSegment);

        // read and parse
        Response resp = read(url);
        AtomFeed feed = parse(resp.getStream(), AtomFeed.class);

        // process tree
        addDescendantsLevel(repositoryId, feed, result);

        return result;
    }

    public List<ObjectParentData> getObjectParents(String repositoryId, String objectId, String filter,
            Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
            Boolean includeRelativePathSegment, ExtensionsData extension) {
        List<ObjectParentData> result = new ArrayList<ObjectParentData>();

        // find the link
        String link = loadLink(repositoryId, objectId, Constants.REL_UP, Constants.MEDIATYPE_FEED);

        if (link == null) {
            // root and unfiled objects have no UP link
            return result;
        }

        UrlBuilder url = new UrlBuilder(link);
        url.addParameter(Constants.PARAM_FILTER, filter);
        url.addParameter(Constants.PARAM_ALLOWABLE_ACTIONS, includeAllowableActions);
        url.addParameter(Constants.PARAM_RELATIONSHIPS, includeRelationships);
        url.addParameter(Constants.PARAM_RENDITION_FILTER, renditionFilter);
        url.addParameter(Constants.PARAM_RELATIVE_PATH_SEGMENT, includeRelativePathSegment);

        // read and parse
        Response resp = read(url);

        AtomBase base = parse(resp.getStream(), AtomBase.class);

        if (base instanceof AtomFeed) {
            // it's a feed
            AtomFeed feed = (AtomFeed) base;

            // walk through the feed
            for (AtomEntry entry : feed.getEntries()) {
                ObjectParentDataImpl objectParent = processParentEntry(entry, repositoryId);

                if (objectParent != null) {
                    result.add(objectParent);
                }
            }
        } else if (base instanceof AtomEntry) {
            // it's an entry
            AtomEntry entry = (AtomEntry) base;

            ObjectParentDataImpl objectParent = processParentEntry(entry, repositoryId);

            if (objectParent != null) {
                result.add(objectParent);
            }
        }

        return result;
    }

    private ObjectParentDataImpl processParentEntry(AtomEntry entry, String repositoryId) {
        ObjectParentDataImpl result = null;
        String relativePathSegment = null;

        lockLinks();
        try {
            // clean up cache
            removeLinks(repositoryId, entry.getId());

            // walk through the entry
            for (AtomElement element : entry.getElements()) {
                if (element.getObject() instanceof AtomLink) {
                    addLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
                } else if (element.getObject() instanceof ObjectData) {
                    result = new ObjectParentDataImpl((ObjectData) element.getObject());
                } else if (is(NAME_RELATIVE_PATH_SEGMENT, element)) {
                    relativePathSegment = (String) element.getObject();
                }
            }
        } finally {
            unlockLinks();
        }

        if (result != null) {
            result.setRelativePathSegment(relativePathSegment);
        }

        return result;
    }

    public ObjectList getCheckedOutDocs(String repositoryId, String folderId, String filter, String orderBy,
            Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
            BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) {
        ObjectListImpl result = new ObjectListImpl();

        // find the link
        String link = loadCollection(repositoryId, Constants.COLLECTION_CHECKEDOUT);

        if (link == null) {
            throw new CmisObjectNotFoundException("Unknown repository or checkedout collection not supported!");
        }

        UrlBuilder url = new UrlBuilder(link);
        url.addParameter(Constants.PARAM_FOLDER_ID, folderId);
        url.addParameter(Constants.PARAM_FILTER, filter);
        url.addParameter(Constants.PARAM_ORDER_BY, orderBy);
        url.addParameter(Constants.PARAM_ALLOWABLE_ACTIONS, includeAllowableActions);
        url.addParameter(Constants.PARAM_RELATIONSHIPS, includeRelationships);
        url.addParameter(Constants.PARAM_RENDITION_FILTER, renditionFilter);
        url.addParameter(Constants.PARAM_MAX_ITEMS, maxItems);
        url.addParameter(Constants.PARAM_SKIP_COUNT, skipCount);

        // read and parse
        Response resp = read(url);
        AtomFeed feed = parse(resp.getStream(), AtomFeed.class);

        // handle top level
        for (AtomElement element : feed.getElements()) {
            if (element.getObject() instanceof AtomLink) {
                if (isNextLink(element)) {
                    result.setHasMoreItems(Boolean.TRUE);
                }
            } else if (isInt(NAME_NUM_ITEMS, element)) {
                result.setNumItems((BigInteger) element.getObject());
            }
        }

        // get the documents
        if (!feed.getEntries().isEmpty()) {
            result.setObjects(new ArrayList<ObjectData>(feed.getEntries().size()));

            for (AtomEntry entry : feed.getEntries()) {
                ObjectData child = null;

                lockLinks();
                try {
                    // clean up cache
                    removeLinks(repositoryId, entry.getId());

                    // walk through the entry
                    for (AtomElement element : entry.getElements()) {
                        if (element.getObject() instanceof AtomLink) {
                            addLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
                        } else if (element.getObject() instanceof ObjectData) {
                            child = (ObjectData) element.getObject();
                        }
                    }
                } finally {
                    unlockLinks();
                }

                if (child != null) {
                    result.getObjects().add(child);
                }
            }
        }

        return result;
    }

    // ---- internal ----

    /**
     * Adds descendants level recursively.
     */
    private void addDescendantsLevel(String repositoryId, AtomFeed feed, List<ObjectInFolderContainer> containerList) {
        if (feed == null || feed.getEntries().isEmpty()) {
            return;
        }

        // walk through the feed
        for (AtomEntry entry : feed.getEntries()) {
            ObjectInFolderDataImpl objectInFolder = null;
            String pathSegment = null;
            List<ObjectInFolderContainer> childContainerList = new ArrayList<ObjectInFolderContainer>();

            lockLinks();
            try {
                // clean up cache
                removeLinks(repositoryId, entry.getId());

                // walk through the entry
                for (AtomElement element : entry.getElements()) {
                    if (element.getObject() instanceof AtomLink) {
                        addLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
                    } else if (element.getObject() instanceof ObjectData) {
                        objectInFolder = new ObjectInFolderDataImpl((ObjectData) element.getObject());
                    } else if (is(NAME_PATH_SEGMENT, element)) {
                        pathSegment = (String) element.getObject();
                    } else if (element.getObject() instanceof AtomFeed) {
                        addDescendantsLevel(repositoryId, (AtomFeed) element.getObject(), childContainerList);
                    }
                }
            } finally {
                unlockLinks();
            }

            if (objectInFolder != null) {
                objectInFolder.setPathSegment(pathSegment);
                ObjectInFolderContainerImpl childContainer = new ObjectInFolderContainerImpl(objectInFolder);
                childContainer.setChildren(childContainerList);
                containerList.add(childContainer);
            }
        }
    }
}
