/**
 *#########################################################################
 *
 * A component of the Gatherer application, part of the Greenstone digital
 * library suite from the New Zealand Digital Library Project at the
 * University of Waikato, New Zealand.
 *
 * <BR><BR>
 *
 * Author: John Thompson, Greenstone Digital Library, University of Waikato
 *
 * <BR><BR>
 *
 * Copyright (C) 1999 New Zealand Digital Library Project
 *
 * <BR><BR>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * <BR><BR>
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * <BR><BR>
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *########################################################################
 */
package org.greenstone.gatherer.shell;

import java.awt.Component;
import java.util.ArrayList;
import org.greenstone.gatherer.Configuration;
import org.greenstone.gatherer.DebugStream;
import org.greenstone.gatherer.Dictionary;
import org.greenstone.gatherer.Gatherer;
import org.greenstone.gatherer.cdm.CollectionDesignManager;
import org.greenstone.gatherer.gui.GProgressBar;
import org.greenstone.gatherer.util.StaticStrings;
/** This implementation of <i>GShellProgressMonitor</i> is designed to parse and translate the progress of a buildcol.pl call.
 * @author John Thompson, Greenstone Digital Library, University of Waikato
 * @version 2.3
 */
/* Wendy's feeble attempt at writing a schedule progress monitor. While it's not really needed, I'm writing it so that the schedule.pl prompts will go away. ;)  This also may need other "ELEMENTS" added to it. 
 */ 

public class GScheduleProgressMonitor
    implements GShellProgressMonitor {
    /** The minimum value = 0 */
    static final private int MIN = 0;
    /** In order to get a smoothish progress bar, set the maximum to a large number = 1000000 */
    static final private int MAX = 1000000;
    /** The various states the Schedule progress state machine can be in, starting at the base state. There are only two stages - perl script generation and cron building - so i'm not sure we need too  many steps. */
    static final int BASE                          = -1;
    static final int SCHEDULE                      =  0;
    static final int DONE                          =  1; 
    /** Now the language independant sentinel strings. */
    static final String SCHEDULE_ELEMENT = "Schedule"; 
    static final String SCHEDULE_DELETE = "Delete"; 
    static final String SCHEDULE_DONE="Done"; 

    static final private String ARGUMENT_ATTRIBUTE = "a";
    static final private String CLASSIFIER_ATTRIBUTE = "c";
    static final private String PLUGIN_ATTRIBUTE = "p";

    /** Indicates if the GUI has asked the process this object monitors to stop. */
    private boolean stop = false;
    /** The current number of stages we have completed. */
    private int current_stages = 0;
    /** The number of stages we are expecting to complete. */
    private int expected_stages = 0;

    private int threshold = Configuration.LIBRARIAN_MODE;
    /** The current state we are in. The state will change depending on the next flag recieved. */
    private int state = BASE;
    /** The progress bar this monitor updates. */
    //private GProgressBar progress_bar;
    /** A progress bar that is shared between this this listener and the Import and build monitor. not sure we need this. */
    //private GProgressBar shared_progress_bar;

    /** Construct a new GScheduleProgressMonitor. */
    public GScheduleProgressMonitor() {
	//this.shared_progress_bar = shared_progress_bar;
	//progress_bar = new GProgressBar();
	//progress_bar.setMaximum(MAX);
	//progress_bar.setMinimum(MIN);
	//progress_bar.setString(null);
	//progress_bar.setStringPainted(true);
	//setValue(MIN);
    }

    /** Method to register a new progress bar with this monitor.
     * @param progress_bar The new <strong>GProgressBar</strong>.
     */	 
    /*note - we don't really need this. Wendy */ 
    public void addProgressBar(GProgressBar progress_bar) {
	//this.progress_bar = progress_bar;
	//progress_bar.setMaximum(MAX);
	//progress_bar.setMinimum(MIN);
	//progress_bar.setStringPainted(false);
	//progress_bar.setString(null);
	//setValue(MIN);
    }

    /** Determine the script exit value according to the progress monitor. This gets around a problem where several script failures actually result with a successful exit value.
     * @return A <i>int</i> with a value of zero if and only if the script was successful.
     */
    public int exitValue() {
	if(state == BASE) {
	    return 0;
	}
	return 1;
    }
    /** Method to retrieve whatever control is being used as the progress indicator. Usually a <strong>GProgressBar</strong> but there may be others implemented later.
     * @return A <strong>Component</strong> on which the progress of the process is being displayed.
     */
    public Component getProgress() {
	//return progress_bar;
	return null;
    }

    public GProgressBar getSharedProgress() {
    //return shared_progress_bar;
    //try returning null;
	return null; 
    }

    public void messageOnProgressBar(String message)
    {
	//if (message!=null && !message.equals("")) {
	    //progress_bar.setString(message);
	    //shared_progress_bar.setString(message);
	//}
        //else {
	    //progress_bar.setString(null);
	    //shared_progress_bar.setString(null);
        //}
    }

    /** Method to determine the state of the stop flag, which may be set by the visual component that created this monitor.
     * @return A <strong>boolean</strong> indicating if the process has been asked to stop.
     */
    public synchronized boolean hasSignalledStop() {
	return stop;
    }
    /** Inform the progress bar that it should programatically increment progress by one step. */
    public void increment() {
	// I'm not sure we really need this for scheduling, so i'm going to ignore it for now.
    }

    /** This method is used to 'feed in' a line of text captured from the process.
     * @param queue a queue which at the moment should contain a single GShellEvent
     */
    public void process(ArrayList queue) {
	GShellEvent event = (GShellEvent) queue.get(0);
	// Remove 'schedule.pl> ' bit
	String line = event.getMessage();
	line = line.substring(line.indexOf(StaticStrings.GREATER_THAN_CHARACTER) + 1);
	line = line.trim();
	// We are only really interested in processing pseudo-XML tags 
	if(line.startsWith(StaticStrings.LESS_THAN_CHARACTER) && line.endsWith(StaticStrings.GREATER_THAN_CHARACTER)) {
	    // All events are vetoed
	    event.veto();
	    
	    // Create a new element from it
	    GShellElement element = new GShellElement(line);
	    // Now change states within the state machine as appropriate. A state change may subsequently incur a progress update.
	    String name = null;
	    String value = null;

		name = element.getElementName(); 
		if(name.equals(SCHEDULE_ELEMENT)) {
		    //progress_bar.setIndeterminate(false);
		    // Produce a lower detail message if required
		    if(Configuration.getMode() <= threshold && !stop) {
			queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Schedule.ScheduleBegun1"), event.getStatus()));
		    }
		}
		else if(name.equals(SCHEDULE_DELETE)) { 
		    if(Configuration.getMode() <= threshold) {
			queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Schedule.ScheduleDelete"), event.getStatus()));
		    }
		}
		else if(name.equals(SCHEDULE_DONE)) { 
		    if(Configuration.getMode() <= threshold) {
			queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Schedule.ScheduleComplete1"), event.getStatus()));
		    }
		} 
		else {
		    // Unknown command, go indeterminate
		    DebugStream.println("Unknown name: " + name);
		    //progress_bar.setIndeterminate(true);
		}



	}
	// If we are dealing with lower detail modes then veto any other messages. We do this here as the progress monitors are garuenteed to recieve this message before anything else
	else if(Configuration.getMode() <= threshold) {
	    event.veto();
	}
    }

    public void reset() {
	current_stages = 0;
	expected_stages = 0;
	//progress_bar.setIndeterminate(false);
	//progress_bar.setString(null);
	setValue(MIN);
	state = BASE;
	//progress_bar.updateUI();
    }

    public void saving() {
    }

    public void setSharedProgressBar(GProgressBar shared_progress_bar) {
    //this.shared_progress_bar = shared_progress_bar;
    }

    /** Since the creator of this process monitor is actually in the GUI, this class provides the simpliest way to send a cancel process message between the two.
     * @param state The desired state of the stop flag as a <strong>boolean</strong>.
     */
    public synchronized void setStop(boolean state) {
	this.stop = state;
	//progress_bar.setIndeterminate(false);
    }
    /** This method resets this monitor to the start, reseting the process parsing and progress bar.
     * TODO Everthing.
     */
    public void start() {
	stop = false;
	setValue(MIN);
	expected_stages = 1; // Always compress text, create info database and auxiliary creation


    }
    /** This method indicates the process is complete. 
     * TODO Everthing.
     */
    public void stop() {
	//progress_bar.setIndeterminate(false);
	setValue(MAX);
    }

    private void setValue(int value) {
	//progress_bar.setValue(value);
	// Incrementing the shared progress bar is a little more problematic as we may very well be trying to set it to MIN but instead set it to halfway if we're not careful.
	//if(value > MIN) {
	//    shared_progress_bar.setValue(MAX + value);
	//}
    }
}

