package de.dtele.messages {
  
  import de.dtele.messages.events.MessageEvent;
  
  import flash.errors.IllegalOperationError;
  import flash.events.EventDispatcher;
  import flash.utils.getQualifiedClassName;
  
  import mx.collections.ArrayCollection;
  
  /**
   * Dispatched when a message has been added
   * 
   * @eventType de.dtele.messages.events.MessageEvent.ADDED
   */
  [Event("messageAdded", type="de.dtele.messages.events.MessageEvent")]
  
  /**
   * Dispatched when a message has been removed
   * 
   * @eventType de.dtele.messages.events.MessageEvent.REMOVED
   */
  [Event("messageRemoved", type="de.dtele.messages.events.MessageEvent")]
  
  /**
   * Manages messages of all kinds and
   * notifies about addition and removal
   * 
   * @author Mathias Brodala
   */
  public final class MessageManager extends EventDispatcher {
    
    /* Properties */
    private static var _instance:MessageManager;
    /**
     * The singleton instance of the message manager
     */
    public static function get instance():MessageManager {
      
      if (_instance == null) {
        
        _instance = new MessageManager();
      }
      
      return _instance;
    }
    
    /**
     * Stack of added messages
     */
    private var _messages:ArrayCollection = new ArrayCollection();
    [Bindable]public function get messages():ArrayCollection {
      return _messages;
    }
    protected function set messages(messages:ArrayCollection):void {
      this._messages = messages;
    }
    
    /* Methods */
    public function MessageManager() {
      
      if (_instance != null) {
        
        throw new IllegalOperationError("Cannot instantiate " + getQualifiedClassName(this) + ". " +
          "Use the singleton instance instead.");
      }
    }
    
    /**
     * Adds a general info message
     * 
     * @param title The short title describing the message
     * @param text The long text describing the message
     * @return The added message
     */
    public function addInfo(title:String, text:String = null):Message {
      
      return this.addMessage(new Message(title, text, Message.INFO));
    }
    
    /**
     * Adds a confirmation message
     * 
     * @param title The short title describing the message
     * @param text The long text describing the message
     * @return The added message
     */
    public function addQuestion(title:String, text:String = null):Message {
      
      return this.addMessage(new Message(title, text, Message.QUESTION));
    }
    
    /**
     * Adds a warning message indicating a recoverable error
     * 
     * @param title The short title describing the message
     * @param text The long text describing the message
     * @return The added message
     */
    public function addWarning(title:String, text:String = null):Message {
      
      return this.addMessage(new Message(title, text, Message.WARNING));
    }
    
    /**
     * Adds a error message indicating a non-recoverable error
     * 
     * @param title The short title describing the message
     * @param text The long text describing the message
     * @return The added message
     */
    public function addError(title:String, text:String = null):Message {
      
      return this.addMessage(new Message(title, text, Message.ERROR));
    }
    
    /**
     * Adds a message
     * 
     * @param message The message to add
     * @return The added message
     */
    public function addMessage(message:Message):Message {
      
      this.messages.addItem(message);
      instance.dispatchEvent(new MessageEvent(MessageEvent.ADDED, message));
      
      return message;
    }
    
    /**
     * Removes a message
     * 
     * @param message The message to remove
     */
    public function removeMessage(message:Message):void {
      
      if (message) {
        
        var index:int = this.messages.getItemIndex(message);
        
        if (index > -1) {
      
          this.messages.removeItemAt(index);
          instance.dispatchEvent(new MessageEvent(MessageEvent.REMOVED, message));
        }
      }
    }
  }
}