/******************************************************************************
    Sort observer
----------------------------------------------------.
Copyright (c) Gunnar Gotshalks. All Rights Reserved.

Permission to use, copy, modify, and distribute this software
and its documentation for NON-COMMERCIAL purposes and
without fee is hereby granted. 
*******************************************************************************/

package FlexOr.searchAndSort;

import java.awt.*;
import java.util.*;

/** A sort observer implements a canvas to show the viewer what it is
observing. */

@SuppressWarnings("serial")
public class SortObserver extends Canvas implements Observer, Runnable {

SortObsData sod;
  SortObservable observed;
  public Integer[] array;
  String sortName;
    
  int x = 20;
  int y = 32;
  int yshift = 5;
  int height = 3;
  int scale = 4;
  int MaxItems = 30;
  int MaxWidth = MaxItems * scale;
  boolean singleStep = false;
  boolean swap;
  int itemCount, comparisonCount, swapCount;
  int sleepTime = 400;
  boolean firstTime = true;
  
  public SortObserver(Object[] array, Observable observed, String sortName) {
    this.array = (Integer[]) array;
    this.observed = (SortObservable) observed;
    this.sortName = sortName;
    observed.addObserver(this);
  }
  
  public void change(int yshift, int height, int scale, int MaxItems,
                     int sleepTime) {
    this.sleepTime = sleepTime;
    this.yshift = yshift;
    this.height = height;
    this.scale = scale;
    this.MaxItems = MaxItems;
    MaxWidth = MaxItems*scale;
  }

  public void paint(Graphics g) { update(g); }
  
  public void newArray() { sod = null; firstTime = true; repaint(); }
  
  protected void drawLegend(Graphics g) {
    g.setColor(Color.white);
    g.fillRect(x+10, y-16, MaxWidth*2, 10);
  
    g.setColor(Color.cyan);
    g.fillRect(x+8, y-16, 47, 12);
    g.setColor(Color.magenta);
    g.fillRect(x+58, y-16, 52, 12);

    g.setColor(Color.black);
    g.drawString(sortName, x-18, y-18);
    g.drawString("#s = " + swapCount, x+10, y-5);
    g.drawString("#c = " + comparisonCount, x+60, y-5);
    g.drawString("#t = " + (swapCount + comparisonCount), x+113, y-5);
  }
  
  protected void clearCanvas(Graphics g) {
      g.setColor(Color.white);
      g.fillRect(0, 0, 2000, 2000);
      firstTime = false;
  }
  
  public void update(Graphics g) {
    int i;
        
    if (firstTime) clearCanvas(g);
    drawLegend(g);
    
    for (i = 0 ; i < array.length ; i++) {
      g.setColor(Color.white);
      g.fillRect(x, y+i*yshift, MaxWidth, height);
      if (sod != null) g.setColor(sod.tag[i]);
      else g.setColor(Color.gray);
      if (array[i] != null) {
        g.fillRect(x, y+i*yshift, array[i].intValue()*scale, height);
      }
    }
  
    g.setColor(Color.white);
    for ( ; i < MaxItems ; i++) { g.fillRect(x, y+i*yshift, MaxWidth, height); }
  }
 
  public synchronized void update(Observable observed, Object paramSod) {
    sod = (SortObsData) paramSod;
    swap = sod.swap;
    if (swap) swapCount++;
    else comparisonCount++;
    if (sod.endOfData) { stop(); }
    else { notify(); }
  }
  
  public synchronized void step() { notify(); }

//*************** Runnable implementation ****************
   
/** Each observer has its own thread. */

   Thread observerThread;
   static int observerCount = 0;
  
/** Runnable interface start method to create a thread for each object of
this class. */

   public void start() { singleStep = false; commonStart(); }
   
   private void commonStart() {
    if (observerThread == null) {
        swapCount = comparisonCount = 0;
        sod = null;
        observerCount++;
        observerThread = new Thread(this, "Observer-" + observerCount);
        observerThread.start();
   }}
   
   public void startSingleStep() { singleStep = true; commonStart(); }

/** Observable stops observer when sort is done. */

  public synchronized void stop() { observerThread = null; notify(); }

/** Wait to be notified of an observation, then display the result of the
observation. */

  public void run() {
      while ( Thread.currentThread() == observerThread) {
          try { synchronized(this) { wait(); } } catch (Exception e) {}
          repaint();
          if (observerThread != null) {
            try { if (singleStep) { synchronized(this) { wait(); } }
                  else Thread.sleep(sleepTime); }
            catch (Exception e) {}
            observed.step();
          }
      }
  }

}

