/*
 * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
 *
 * The contents of this file are subject to the CCM Public
 * License (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.redhat.com/licenses/ccmpl.html.
 *
 * Software distributed under the License is distributed on an
 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
 * or implied. See the License for the specific language
 * governing rights and limitations under the License.
 *
 */
package com.arsdigita.cms.ui.revision;

import com.arsdigita.cms.ContentItem;
import com.arsdigita.cms.util.GlobalizationUtil;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.kernel.ACSObject;
import com.arsdigita.persistence.OID;
import com.arsdigita.persistence.metadata.ObjectType;
import com.arsdigita.persistence.metadata.Property;
import com.arsdigita.versioning.Difference;
import org.apache.log4j.Logger;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * @author Justin Ross &lt;jross@redhat.com&gt;
 * @version $Id: //cms/dev/src/com/arsdigita/cms/ui/revision/OperationIterator.java#8 $
 */
class OperationIterator {
    public static final String versionId =
        "$Id: //cms/dev/src/com/arsdigita/cms/ui/revision/OperationIterator.java#8 $" +
        "$Author: dennis $" +
        "$DateTime: 2004/04/07 16:07:11 $";

    private static final Logger s_log = Logger.getLogger
        (OperationIterator.class);

    private final Iterator m_operations;

    OperationIterator(final Difference diff) {
        final Iterator changes = diff.getChanges().iterator();

        final ArrayList operations = new ArrayList();

        while (changes.hasNext()) {
            final Difference.Change change =
                (Difference.Change) changes.next();

            final ObjectType type = change.getOID().getObjectType();

            String name;

            if (type.hasProperty("displayName")) {
                name = String.valueOf
                    (change.getTo(type.getProperty("displayName")));
            } else {
                name = type.toString();
            }

            final Iterator props = type.getProperties();

            while (props.hasNext()) {
                final Property prop = (Property) props.next();
                final Object from = change.getFrom(prop);
                final Object to = change.getTo(prop);

                if (blacklisted(prop)) continue;
                if (!change.isModified(prop)) continue;
                if (from == null && to == null) continue;
                if (from != null && from.equals(to)) continue;
                if (to != null && to.equals(from)) continue;

                final Iterator added = change.getAdded(prop).iterator();

                StringBuffer buffer = new StringBuffer();

                while (added.hasNext()) {
                    buffer.append(prettify(added.next(), change));
                    buffer.append(", ");
                }

                String adds = buffer.toString();

                if (adds.endsWith(", ")) {
                    adds = adds.substring(0, adds.length() - 2);
                }

                final Iterator removed = change.getRemoved(prop).iterator();

                buffer = new StringBuffer();

                while (removed.hasNext()) {
                    buffer.append(prettify(removed.next(), change));
                    buffer.append(", ");
                }

                String removes = buffer.toString();

                if (removes.endsWith(", ")) {
                    removes = removes.substring(0, removes.length() - 2);
                }

                final Object[] operation = new Object[] {
                    prettify(change.getOID(), change),
                    capitalize(prop.getName()),
                    new Boolean(prop.isCollection()),
                    prettify(from, change),
                    prettify(to, change),
                    adds,
                    removes
                };

                operations.add(operation);
            }
        }

        m_operations = operations.iterator();
    }

    private String prettify(final Object obj,
                            final Difference.Change change) {
        if (obj == null) {
            return lz("cms.ui.item.revision.nothing");
        } else if (obj instanceof String) {
            return quote(obj);
        } else if (obj instanceof OID) {
            return name((OID) obj, change);
        } else {
            return obj.toString();
        }
    }

    private String quote(final Object obj) {
        return "\"" + obj + "\"";
    }

    private String name(final OID oid, final Difference.Change change) {
        final ObjectType type = oid.getObjectType();

        if (type.hasProperty(ACSObject.DISPLAY_NAME)) {
            return String.valueOf
                (change.getTo(type.getProperty(ACSObject.DISPLAY_NAME)));
        } else {
            return type.toString();
        }
    }

    private boolean blacklisted(final Property prop) {
        final String name = prop.getName();

        return (name.equals(ContentItem.CHILDREN)
                || name.equals(ContentItem.CONTENT_SECTION));
    }

    private String capitalize(final String str) {
        if (str == null) {
            return "";
        } else if (str.length() == 0) {
            return "";
        } else {
            return str.substring(0, 1).toUpperCase() + str.substring(1);
        }
    }

    final boolean hasNext() {
        return m_operations.hasNext();
    }

    final Object[] next() {
        return (Object[]) m_operations.next();
    }

    private static GlobalizedMessage gz(final String key) {
        return GlobalizationUtil.globalize(key);
    }

    private static String lz(final String key) {
        return (String) gz(key).localize();
    }
}
