/11/ design patterns: Observer implementation (example)
// PACKAGE
AsSetupPackage("org.moock.logger");

// CLASS Logger EXTENDS org.moock.util.Observable

/**
 * A general log class. Use getLog() to create an app-wide instance.
 * Send messages with fatal(), error(), warn(), info(), and debug().
 * Add views for the log with addObserver() (views must implement Observer).
 * 
 * @version 1.0.0
 */

org.moock.logger.Logger = function () {
  // Show "INFO" level messages by default.
  this.setLevel("INFO");   
}

// SET SUPERCLASS
org.moock.logger.Logger.prototype = new org.moock.util.Observable();

// STATIC PROPERTIES

// A reference to the log instance (Singleton).
org.moock.logger.Logger.log = null;

// The valid severity levels for logged messages.
org.moock.logger.Logger.logLevels = ["FATAL", 
                                     "ERROR", 
                                     "WARN", 
                                     "INFO", 
                                     "DEBUG"];

// INSTANCE PROPERTIES

// The zero-relative filter level for the log. 
// Messages with a level above logLevel will 
// not be passed on to observers.
// Default is 3, "INFO" (only DEBUG messages are filtered out.
org.moock.logger.Logger.prototype.logLevel = null;


// STATIC METHODS
  /**
   * Returns a reference to the log instance.
   * If no log instance exists yet, creates one.
   */
  org.moock.logger.Logger.getLog = function () {
    if (org.moock.logger.Logger.log == null) {
      org.moock.logger.Logger.log = new org.moock.logger.Logger();
    }
    return org.moock.logger.Logger.log;  
  }

// INSTANCE METHODS
  /**
   * Sets the message filter level for the log.
   *
   * @param   l   The level above which messages are filtered out.
   */
  org.moock.logger.Logger.prototype.setLevel = function (l) {
    // Find the specified level in the logLevel array.
    for (var i = 0; i < org.moock.logger.Logger.logLevels.length; i++) {
      if (org.moock.logger.Logger.logLevels[i].toLowerCase() == l.toLowerCase()) {
        // Found the human-readable level, now set it as an integer.
        this.logLevel = i;
        this.info("Log level set to: " + org.moock.logger.Logger.logLevels[i]);
        // We found the log level, so quit looking.
        return;
      }
    }

    // No log level by the specified name was found.
    this.warn("Invalid log level specified.");
  }

  /**
   * Returns the human-readable message filter level for the log.
   */
  org.moock.logger.Logger.prototype.getLevel = function () {
	return org.moock.logger.Logger.logLevels[this.logLevel];
  }

  /**
   * Sends a message to the log, with severity "FATAL".
   */
  org.moock.logger.Logger.prototype.fatal = function (msg) {
    // If the filter level is at least "FATAL", then 
    // broadcast the message to observers.
    if (this.logLevel >= 0) {
      // Construct the log message object.
      var lm = new org.moock.logger.LogMessage(msg, "FATAL");

      // Pass the message on to observers.
      this.setChanged();
      this.notifyObservers(lm);
    }
  }

  /**
   * Sends a message to the log, with severity "ERROR".
   */
  org.moock.logger.Logger.prototype.error = function (msg) {
    // If the filter level is at least "ERROR", then 
    // broadcast the message to observers.
    if (this.logLevel >= 1) {
      var lm = new org.moock.logger.LogMessage(msg, "ERROR");

      this.setChanged();
      this.notifyObservers(lm);
    }
  }

  /**
   * Sends a message to the log, with severity "WARN".
   */
  org.moock.logger.Logger.prototype.warn = function (msg) {
    // If the filter level is at least "WARN", then 
    // broadcast the message to observers.
    if (this.logLevel >= 2) {
      var lm = new org.moock.logger.LogMessage(msg, "WARN");

      this.setChanged();
      this.notifyObservers(lm);
    }
  }
  
  /**
   * Sends a message to the log, with severity "INFO".
   */
  org.moock.logger.Logger.prototype.info = function (msg) {
    // If the filter level is at least "INFO", then 
    // broadcast the message to observers.
    if (this.logLevel >= 3) {
      var lm = new org.moock.logger.LogMessage(msg, "INFO");
      this.setChanged();
      this.notifyObservers(lm);
    }
  }

  /**
   * Sends a message to the log, with severity "DEBUG".
   */
  org.moock.logger.Logger.prototype.debug = function (msg) {
    // If the filter level is at least "DEBUG", then 
    // broadcast the message to observers.
    if (this.logLevel >= 4) {
      var lm = new org.moock.logger.LogMessage(msg, "DEBUG");

      this.setChanged();
      this.notifyObservers(lm);
    }
  }
// PACKAGE
AsSetupPackage("org.moock.logger");

// CLASS LogMessage

/**
 * A log message. Sent by the the Logger to all registered log observers
 * when a new log message is generated.
 */
org.moock.logger.LogMessage = function (m, l) {
  this.setMessage(m);
  this.setLevel(l);
}


// PROPERTIES

// The actual message sent to the log.
org.moock.logger.LogMessage.prototype.msg = null;

// The severity level of this message (one of: "FATAL", "ERROR", 
// "WARN", "INFO", "DEBUG");
org.moock.logger.LogMessage.prototype.lev = null;


// METHODS

  /**
   * Sets the log message.
   */
  org.moock.logger.LogMessage.prototype.setMessage = function (m) {
    this.msg = m;
  }

  /**
   * Returns the log message.
   */
  org.moock.logger.LogMessage.prototype.getMessage = function () {
    return this.msg;
  }

  /**
   * Sets the severity level for this message.
   */
  org.moock.logger.LogMessage.prototype.setLevel = function (l) {
    this.lev = l;
  }

  /**
   * Returns the severity level for this message.
   */
  org.moock.logger.LogMessage.prototype.getLevel = function () {
    return this.lev;
  }
// PACKAGE
AsSetupPackage("org.moock.logger");

// CLASS OutputWindowView IMPLEMENTS org.moock.util.Observer

/**
 * An observer of the Logger class. When a movie is played in 
 * the Flash authoring tool's Test Movie mode, this class displays
 * messages sent to the log in the Output window.
 */

org.moock.logger.OutputWindowView = function (l) {
  this.log_model = l;
}

// PROPERTIES

// The log that this object is observing.
org.moock.logger.OutputWindowView.prototype.log_model = null;

// METHODS

  /**
   * Invoked when the log changes. For details, see the 
   * Observer interface.
   */
  org.moock.logger.OutputWindowView.prototype.update = function (o, infoObj) {
    trace(infoObj.getLevel() + ": " + infoObj.getMessage());
  }
// PACKAGE
AsSetupPackage("org.moock.logger");

// CLASS TextFieldView IMPLEMENTS org.moock.util.Observer

/**
 * An observer of the Logger class. This class displays
 * messages sent to the log in a text field.
 */

org.moock.logger.TextFieldView = function (l,
                                 target, 
                                 depth, 
                                 x,
                                 y,
                                 w,
                                 h) {

    this.log_model = l;
    this.target = target;
    this.makeTextField(this.target, depth, x, y, w, h);
}

// PROPERTIES

// The log that this object is observing.
org.moock.logger.TextFieldView.prototype.log_model = null;

// The movie clip in which the text field will be created.
org.moock.logger.TextFieldView.prototype.target = null;

// A reference to the text field.
org.moock.logger.TextFieldView.prototype.out = null;


// METHODS
  /**
   * Invoked when the log changes. For details, see the 
   * Observer interface.
   */
  org.moock.logger.TextFieldView.prototype.update = function (o, infoObj) {
    // Display the log message in the log text field.
    this.out.text += infoObj.getLevel() + ": " + infoObj.getMessage()  + "\n";
    // Scroll to the bottom of the log text field.
    this.out.scroll = this.out.maxscroll;
  }

  /**
   * Creates a text field in the specified movie clip at
   * the specified depth. Log messages are displayed in the text field.
   */
  org.moock.logger.TextFieldView.prototype.makeTextField = function (target, 
                              depth,
                              x,
                              y,
                              w,
                              h) {
    // Create the text field.
    this.target.createTextField("log_txt", depth, x, y, w, h);
    // Store a reference to the text field.
    this.out = this.target.log_txt;
    // Put a border on the text field.
    this.out.border = true;
    // Make the text in the text field wrap.
    this.out.wordWrap = true;
  }
#include "../org/moock/lang/AsSetupPackage.as"
#include "../org/moock/util/Observable.as"
#include "../org/moock/logger/Logger.as"
#include "../org/moock/logger/LogMessage.as"
#include "../org/moock/logger/OutputWindowView.as"
#include "../org/moock/logger/TextFieldView.as"

// Grab a reference to the log.
var log = org.moock.logger.Logger.getLog();

// Create log observers.
var outputWinLog = new org.moock.logger.OutputWindowView(log);
log.addObserver(outputWinLog);

var textLog = new org.moock.logger.TextFieldView(log, this, 0, 100, 100, 300, 200);
log.addObserver(textLog);

// This won't display because the log
// severity level is set to "INFO".
log.debug("Testing...");  

// Try the levels that are allowed by severity level "INFO".
log.info("Log started.");
log.warn("This is a test warning.");
log.error("This is a test error.");
log.fatal("This is a test fatal error notification.");

// Now tell the log to display messages with
// severity of "DEBUG".
log.setLevel("DEBUG");   
log.debug("Testing...");  // Works now!