
import java.net.*;
import java.io.*;
import java.util.*;

/** This class manages the process of carrying out a set of 
 *  tasks. These tasks may each take some time and may
 *  possibly fail. The class makes
 *  the tasks which have been done available to other classes incrementally
 *  as they become available. This allows an application to
 *  start using the results of the task which are available without 
 *  waiting for the whole process to complete.
 *  @see: "SoundDownloadManager", "TaskManager" etc 
 */
public class TaskManager extends Object implements Runnable
{
  //--------------------------------------------
  /** A set of Tasks to be carried out. */
  private ArrayList taskList; 
  //--------------------------------------------
  /** represents those downloads which were successful */
  private ArrayList goodTasks;
  //--------------------------------------------
  /** represents those downloads which were not successful */
  private ArrayList badTasks;

  //--------------------------------------------
  /** This set contains those Tasks which have been
   *  done since another class has called the 
   *  getFresh method */
  private ArrayList freshTasks;
  //--------------------------------------------
  /** This flag gets set when a new task is successful done */
  private boolean hasFreshTasks;
  //--------------------------------------------
  private Thread taskThread;
  //--------------------------------------------
  private Date startTime;
  //--------------------------------------------
  private Date finishTime;
  //--------------------------------------------
  private boolean hasFinished;
  //--------------------------------------------
  private static String NEWLINE = System.getProperty("line.separator");


  //--------------------------------------------
  /** a constructor which doesnt do much */
  public TaskManager()
  {
    this.hasFreshTasks = false;
    this.taskList = new ArrayList();
    this.goodTasks = new ArrayList();
    this.badTasks = new ArrayList();
    this.freshTasks = new ArrayList();
    this.hasFinished = false;
  } //-- constr: ()

  //--------------------------------------------
  public TaskManager(Task[] aaTasks)
  {
    this();
    for (int ii = 0; ii < aaTasks.length; ii++)
    {
      this.taskList.add(aaTasks[ii]);
    }
  } //-- constr: (tasks[])


  //--------------------------------------------
  /** adds a task to be managed */
  public void addTask(Task newTask)
  {
    this.taskList.add(newTask);
  }

  //--------------------------------------------
  /**  */
  public boolean hasFinished()
  {
    return this.hasFinished;
  }

  //--------------------------------------------
  /** informs how long the manager has been working, milliseconds */
  public long getDuration()
  {
    
    if (this.startTime == null)
     { return 0; }

    if (this.finishTime == null)
    {
      Date dNow = new Date();
      return dNow.getTime() - this.startTime.getTime();
    }

    return this.finishTime.getTime() - this.startTime.getTime();

  } //-- method getDuration

  //--------------------------------------------
  public int completedTasks()
  {
    return this.goodTasks.size() + this.badTasks.size();
  }

  //--------------------------------------------
  /** tell the number of successful tasks */
  public int countGoodTasks()
   { return this.goodTasks.size(); }
  
  //--------------------------------------------
  /** tell the number of unsuccessful tasks */
  public int countBadTasks()
   { return this.badTasks.size(); }    
  


  //--------------------------------------------
  /** allows another class to know if this class has
   *  download new resource files and if it is worth
   *  calling the getFreshTasks method */

  public boolean hasFreshTasks()
   { return this.hasFreshTasks;  }

  //--------------------------------------------
  /** retrieves the successful Tasks */
  public ArrayList getGoodTasks()
   { return this.goodTasks; }    
  
  //--------------------------------------------
  /** retrieves the unsuccessful Tasks */
  public ArrayList getBadTasks()
   { return this.badTasks; }    

  //--------------------------------------------
  /**
   * returns those Tasks which have been retrieved since
   * the last call to this method.   */ 
  public ArrayList getFreshTasks() 
  {
    ArrayList aaReturn = new ArrayList();
    Iterator ii = this.freshTasks.iterator();
    while (ii.hasNext())
    {
      aaReturn.add((Task)ii.next());
    }

    this.freshTasks.clear();
    this.hasFreshTasks = false;
    return aaReturn; 
  }

  //--------------------------------------------
  public void run()
  {
    this.doTasks();
  }

  //--------------------------------------------
  /** starts the task thread */ 
  public void startTasks()
  {
    this.taskThread = new Thread(this);
    this.taskThread.start();
  } //-- method: startTasks()


  //--------------------------------------------
  /** does all of the tasks */ 
  public void doTasks()
  {
    this.startTime = new Date();

    Task tCurrent;
    Iterator ii = this.taskList.iterator();

    while (ii.hasNext())
    {
      tCurrent = (Task)ii.next();
      tCurrent.doTask();
      if (tCurrent.wasSuccessful())
      {
        this.goodTasks.add(tCurrent);
        this.freshTasks.add(tCurrent);
        this.hasFreshTasks = true; 
      }
      else
      {
        this.badTasks.add(tCurrent);
      } //-- if, else       
    } //-- while

    this.finishTime = new Date();
    this.hasFinished = true;

  } //-- method: startDownloading()



  //--------------------------------------------
  public String print()
  { 
    StringBuffer sbReturn = new StringBuffer();
    return this.toString();
  }


  //--------------------------------------------
  /** displays a concise summary. */
  public String toString() 
  {
    StringBuffer sbReturn = new StringBuffer();
    Task tCurrentTask;

    sbReturn.append("Task Manager: ");

    sbReturn.append("(");
    sbReturn.append(this.taskList.size());
    sbReturn.append(" loads, ");
    sbReturn.append("successful:");
    sbReturn.append(this.countGoodTasks());
    sbReturn.append(", failed:");
    sbReturn.append(this.countBadTasks());
    sbReturn.append(", time taken:");
    sbReturn.append((float)this.getDuration()/1000);
    sbReturn.append(" secs");
    sbReturn.append(")");


    if (this.startTime != null)
    {
      sbReturn.append(" started at:");
      sbReturn.append(this.startTime);
    }

    if (this.finishTime != null)
    {
      sbReturn.append(" -finished-");
    }
    else
    {
      sbReturn.append(" -not started-");
    }

    return sbReturn.toString();
  } //-- method: toString


  //--------------------------------------------
  /**
   * prints information about all the attempts to download resources.
   *
   * @see "the toString() and printFullReport() methods"
   * @return a string which is suitable for displaying somewhere
   */
  public String printReport() 
  {
    StringBuffer sbReturn = new StringBuffer();

    Task tCurrentTask;


    sbReturn.append("-Task Manager-");
    sbReturn.append(NEWLINE);
    sbReturn.append("successful :");
    sbReturn.append(this.countGoodTasks());
    sbReturn.append(NEWLINE);
    sbReturn.append("failed     :");
    sbReturn.append(this.countBadTasks());
    sbReturn.append(NEWLINE);

    if (this.startTime == null)
    {
      sbReturn.append("start time  :");
      sbReturn.append(" -not started-");
    }
    else
    {
      sbReturn.append("work time   :");
      sbReturn.append((float)this.getDuration()/1000);
      sbReturn.append(" secs");
      sbReturn.append(NEWLINE);
      sbReturn.append("start time  :");
      sbReturn.append(this.startTime);
    }

    sbReturn.append(NEWLINE);

    if (this.finishTime == null)
    {
      sbReturn.append("finish time :");
      sbReturn.append(" -not finished-");
    }
    else
    {
      sbReturn.append("finish time :");
      sbReturn.append(this.finishTime);
    }

    sbReturn.append(NEWLINE);
    sbReturn.append(NEWLINE);

    Iterator ii;

    ii = this.goodTasks.iterator();
    while (ii.hasNext()) 
    {
      sbReturn.append("* ");
      tCurrentTask = (Task)ii.next();
      sbReturn.append(tCurrentTask.toString());
      sbReturn.append(NEWLINE);
    } //-- while

    //sbReturn.append("--failed --");
    //sbReturn.append(NEWLINE);

    ii = this.badTasks.iterator();
    while (ii.hasNext()) 
    {
      sbReturn.append("* ");
      tCurrentTask = (Task)ii.next();
      sbReturn.append(tCurrentTask.toString());
      sbReturn.append(NEWLINE);
    } //-- while

    return sbReturn.toString();

  } //-- method: printReport


  //--------------------------------------------
  /** allows the display of information about all the attempts
   *  to download resources from the internet. */
  public String printFullReport() 
  {
    StringBuffer sbReturn = new StringBuffer();

    Task tCurrentTask;


    sbReturn.append("**Task Manager**");
    sbReturn.append(NEWLINE);
    sbReturn.append("Total Successful Tasks :");
    sbReturn.append(this.countGoodTasks());
    sbReturn.append(NEWLINE);
    sbReturn.append("Total Failed Tasks :");
    sbReturn.append(this.countBadTasks());
    sbReturn.append(NEWLINE);
    sbReturn.append(NEWLINE);

    sbReturn.append("--successful tasks--");
    sbReturn.append(NEWLINE);
    Iterator ii;

    ii = this.goodTasks.iterator();
    while (ii.hasNext()) 
    {
      sbReturn.append(NEWLINE);
      tCurrentTask = (Task)ii.next();
      sbReturn.append(tCurrentTask.printReport());
    } //-- while

    sbReturn.append("--failed tasks--");
    sbReturn.append(NEWLINE);

    ii = this.badTasks.iterator();
    while (ii.hasNext()) 
    {
      sbReturn.append(NEWLINE);
      tCurrentTask = (Task)ii.next();
      sbReturn.append(tCurrentTask.printReport());
    } //-- while

    return sbReturn.toString();
  } //-- method: printFullReport


  //--------------------------------------------
  public static void main(String[] args) throws Exception
  {
    StringBuffer sbUserMessage = new StringBuffer("");
    sbUserMessage.append("test usage: java TaskManager .");


    if (args.length == 0)
    {
      System.out.println(sbUserMessage);
      System.exit(-1);
    }

    TaskManager dmTest = new TaskManager();

    Task tDownload1 = new WebDownload("http://www.yahoo.com");
    Task tDownload2 = new WebDownload("http://www.google.com");
    Task tDownload3 = new WebDownload("http://www.geocities.com");
    dmTest.addTask(tDownload1);
    dmTest.addTask(tDownload2);
    dmTest.addTask(tDownload3);

    dmTest.startTasks();
    long l = 500;
    Task tCurrent;
    boolean bFlag = true;

    ArrayList tasks;

    while (!dmTest.hasFinished())
    {
      if (dmTest.hasFreshTasks() && bFlag)
      {
        System.out.println("Fresh tasks :" + dmTest.hasFreshTasks());
        tasks = dmTest.getFreshTasks();
        
      }
    }


    System.out.println(dmTest.printReport());
    System.out.println(dmTest.toString());
      
  
  } //-- main()
} //-- TaskManager class
