/*
 * 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.search;


import com.arsdigita.cms.CMS;
import com.arsdigita.cms.ContentPage;
import com.arsdigita.search.ContentType;
import com.arsdigita.search.ContentProvider;

import com.arsdigita.domain.DomainObjectTextRenderer;
import com.arsdigita.domain.DomainObjectTraversal;
import com.arsdigita.domain.DomainObject;
import com.arsdigita.persistence.DataObject;
import com.arsdigita.persistence.DataAssociation;
import com.arsdigita.cms.TextAsset;
import com.arsdigita.persistence.metadata.ObjectType;
import com.arsdigita.persistence.metadata.Property;
import com.arsdigita.domain.DomainServiceInterfaceExposer;
import com.arsdigita.cms.FileAsset;
import com.arsdigita.util.StringUtils;
import com.arsdigita.search.converter.ConverterRegistry;
import com.arsdigita.search.converter.ConversionException;
import com.arsdigita.search.converter.Converter;
import org.apache.log4j.Logger;

public class ContentPageTextContentProvider implements ContentProvider {

    private ContentPage m_page;
    private String m_context;

    public ContentPageTextContentProvider(String context,
                                          ContentPage page) {
        m_context = context;
        m_page = page;
    }

    public String getContext() {
        return m_context;
    }

    public ContentType getType() {
        return ContentType.TEXT;
    }

    public byte[] getBytes() {
        
        // Long term, this should be uncommented and the conversion
        // should be moved in to the com.arsdigita.search package.
        // But, for now, this is faster/easier
        //DomainObjectTextRenderer renderer =
        //    new DomainObjectTextRenderer();
        TextRenderer renderer = new TextRenderer();

        renderer.walk(m_page, ContentPageMetadataProvider.class.getName());

        String text = renderer.getText();
        return text.getBytes();
    }

    /**
     * An implementation of the traversal code that converts FileAssets in
     * to the appropriate text
     */
    public class TextRenderer extends DomainObjectTraversal {
        
        private Logger s_log = Logger.getLogger(TextRenderer.class);
        private StringBuffer m_text;

        /**
         */
        public TextRenderer() {
            m_text = new StringBuffer("");
        }

        public String getText() {
            return m_text.toString();
        }

        protected void beginObject(DomainObject obj,
                                   String path) {
        }

        protected void endObject(DomainObject obj,
                                 String path) {
        }

        protected void revisitObject(DomainObject obj,
                                     String path) {
        }

        protected void handleAttribute(DomainObject obj,
                                       String path,
                                       Property property) {

            Object value = 
                DomainServiceInterfaceExposer.get(obj, property.getName());

            if (value != null &&
                property.isRole() && 
                (value instanceof DataObject)) {
                
                ObjectType assetType = ((DataObject)value).getOID().getObjectType();
                String assetTypeName = assetType.getQualifiedName();
                if (assetTypeName.equals(TextAsset.BASE_DATA_OBJECT_TYPE)) {
                    // add the value of the text asset to search_content
                    appendTextAsset(new TextAsset((DataObject)value));
                    
                } else if (assetTypeName.equals(FileAsset.BASE_DATA_OBJECT_TYPE)) {
                    // add the value of the file asset to search_content
                    FileAsset fa = new FileAsset((DataObject)value);
                    appendFileAsset(fa);
                }
            } else {
                if (value != null && !property.isRole()) {
                    m_text.append(" " + value);
                }
            }
        }

        protected void beginRole(DomainObject obj,
                                 String path,
                                 Property property) {
        }

        protected void endRole(DomainObject obj,
                               String path,
                               Property property) {
        }


        protected void beginAssociation(DomainObject obj,
                                        String path,
                                        Property property) {
            DataAssociation association = 
                (DataAssociation)DomainServiceInterfaceExposer.get
                (obj, property.getName());
            
            if (association != null && 
                association.getObjectType().isSubtypeOf
                (FileAsset.BASE_DATA_OBJECT_TYPE)) {
                while (association.next()) {
                    // add the value of the file asset to search_content
                    appendFileAsset(new FileAsset(association.getDataObject()));
                }
            } else if (association != null && 
                association.getObjectType().isSubtypeOf
                (TextAsset.BASE_DATA_OBJECT_TYPE)) {
                while (association.next()) {
                    // add the value of the file asset to search_content
                    appendTextAsset(new TextAsset(association.getDataObject()));
                }
            }
        }
        
        protected void endAssociation(DomainObject obj,
                                      String path,
                                      Property property) {
        }

        private void appendTextAsset(TextAsset asset) {
            String content = asset.getText();
            if (content != null) {
                m_text.append(" " + StringUtils.htmlToText(content));
            }
        }

        private void appendFileAsset(FileAsset asset) {
            Converter converter = 
                ConverterRegistry.getConverter(asset.getMimeType());
            if (converter != null) {
                try {
                    m_text.append
                        (" " +
                         converter.convertDocument(asset.getContent()));
                } catch (ConversionException e) {
                    s_log.error("Error converting FileAsset " + asset.getOID()+
                                " with MimeType " + asset.getMimeType(), e);
                }
            } else {
                s_log.debug("Skipping FileAsset " + asset.getOID() +
                            " with MimeType " + asset.getMimeType());
            }
        }
    }
}
