/* ======================================================================
   Parts Copyright 2006 University of Leeds, Oxford University, University of the Highlands and Islands.

   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.bodington.installation;

import java.util.Enumeration;

import org.apache.log4j.Logger;
import org.bodington.server.BuildingServerException;
import org.bodington.server.BuildingSession;
import org.bodington.server.BuildingSessionManagerImpl;
import org.bodington.server.JobScheduler;
import org.bodington.server.JobSession;
import org.bodington.server.resources.Resource;
import org.bodington.server.resources.ResourceTree;
import org.bodington.server.resources.ResourceTreeManager;

/**
 * This class rebuilds the metadata for all the resources in the Tree.
 * @author buckett
 */
public class MetadataBuilder implements JobSession
{
    private static Logger log = Logger.getLogger(MetadataBuilder.class);
    
    /**
     * Entry point for JobScheduler.
     * @param args Should be an empty string as it is currently ignored.
     */
    public void rebuild(String args)
    {
        try
        {
            log.info("Starting rebuild of metadata.");
            
            ResourceTree tree = ResourceTreeManager.getInstance();
            
            Resource root = tree.findRootResource();
            int total = updateMetadataAndChildren(root);
            
            log.info("Updated the metadata of "+ total+ " resources.");
            
        }
        catch (BuildingServerException bse)
        {
            log.error("Couldn't startup.", bse);
        }
    }
    
    /**
     * Regenerated the metadata for the selected resource.
     * @param resource The resource to regenrate the metadata for.
     * @return True if we sucessfully updated the metadata.
     */
    private boolean updateMetadata(Resource resource)
    {
        try
        {
        BuildingSession session = BuildingSessionManagerImpl.getSession(resource);
        session.updateBasicMetadata();
        return true;
        }
        catch (Exception e)
        {
            log.warn("Failed to update resource: "+ resource.getPrimaryKey(), e);
            
        }
        return false;
    }
    
    /**
     * Update the metadata for this resource and walks through all children updating.
     * @param resource The resource to start from.
     * @return The number of resources updated.
     */
    private int updateMetadataAndChildren(Resource resource)
    {
        int updated = 0;
        if (updateMetadata(resource))
            updated++;
        try
        {
        Enumeration children = resource.findChildren();
        while (children.hasMoreElements())
        {
            updated += updateMetadataAndChildren((Resource)children.nextElement());
        }
        }
        catch (BuildingServerException bse)
        {
            log.warn("Problem finding children of resource: "
                + resource.getPrimaryKey(), bse);
        }
        return updated;
    }
    
    /**
     * Check that we have been run at least once. Even if the database is cleanly 
     * created this needs to be run so that things like the site and admin building get
     * metadata.
     */
    public static void addJob()
    {
        try
        {
            JobScheduler.getJobScheduler(true).addJobOnce(MetadataBuilder.class.getName(), "rebuild");
        }
        catch (BuildingServerException bse)
        {
            log.error("Problem finding job or adding a new one.", bse);
        }
    }

}
