package de.dtele.net {
  
  import com.adobe.crypto.SHA1;
  
  import de.dtele.data.Credentials;
  import de.dtele.data.IResource;
  import de.dtele.net.events.MediaRequestEvent;
  
  import flash.events.Event;
  import flash.events.EventDispatcher;
  import flash.events.ProgressEvent;
  import flash.net.FileReference;
  import flash.utils.Dictionary;
  
  /**
   * Dispatched when a request was successfully completed
   * 
   * @eventType flash.events.Event
   */
  [Event("complete", type="flash.events.Event")]
  
  /**
   * Dispatched when progress on a request occurs
   * 
   * @eventType flash.events.ProgressEvent
   */
  [Event("progress", type="flash.events.ProgressEvent")]
  
  /**
   * Dispatched when a request was cancelled
   * 
   * @eventType flash.events.Event
   */
  [Event("cancel", type="flash.events.Event")]
  
  /**
   * General object for all requests complying to the MediaRequest API
   * 
   * @author Mathias Brodala
   */
  public class MediaRequest extends EventDispatcher {
    
    /* Constants */
    /**
     * The supported version of the MediaRequest API
     */
    public static const VERSION:Number = 1.0;
    /**
     * General information about a source
     */
    public static const INFO:String = "info";
    /**
     * List of resources provided by a source
     */
    public static const LIST:String = "list";
    /**
     * Add resources to a source
     */
    public static const ADD:String = "add";
    /**
     * Remove resources from a source
     */
    public static const REMOVE:String = "remove";
    
    /* Properties */
    /**
     * The version of the MediaRequest API this request conforms to
     */
    public function get version():Number { return MediaRequest.VERSION; }
    
    private var _type:String;
    /**
     * The type of this request
     */
    public function get type():String { return this._type; }
    
    private var _id:String;
    /**
     * An optional identifier, useful for transactions
     */
    public function get id():String { return this._id; }
    
    private var _resources:Object = {};
    /**
     * Resources attached to this request
     */
    public function get resources():Object { return this._resources; }
    public function set resources(resources:Object):void { this._resources = resources; }
    
    private var _files:Vector.<FileReference> = new Vector.<FileReference>();
    /**
     * Files attached to this request
     */
    public function get files():Vector.<FileReference> { return _files; }
    public function set files(files:Vector.<FileReference>):void { this._files = files; }
    
    private var _credentials:Credentials;
    /**
     * Credentials attached to this request
     */
    public function get credentials():Credentials { return _credentials; }
    public function set credentials(credentials:Credentials):void { this._credentials = credentials; }
    
    private var _bytesLoaded:Number;
    [Bindable]
    /**
     * Number of loaded bytes
     */
    public function get bytesLoaded():Number { return this._bytesLoaded; }
    /**
     * @private
     */
    public function set bytesLoaded(value:Number):void {
      
      if (value != this._bytesLoaded) {
        
        this._bytesLoaded = value;
        
        if (value == this.bytesTotal) {
          
          this.dispatchEvent(new Event(Event.COMPLETE));
        } else {
        
          this.dispatchEvent(new ProgressEvent(
            ProgressEvent.PROGRESS,
            false,
            false,
            this.bytesLoaded,
            this.bytesTotal
          ));
        }
      }
    }
    
    private var _bytesTotal:Number;
    [Bindable]
    /**
     * Number of total bytes
     */
    public function get bytesTotal():Number { return this._bytesTotal; }
    /**
     * @private
     */
    public function set bytesTotal(value:Number):void {
      
      if (value != this._bytesTotal) {
        
        this._bytesTotal = value;
        
        this.dispatchEvent(new ProgressEvent(
          ProgressEvent.PROGRESS,
          false,
          false,
          this.bytesLoaded,
          this.bytesTotal
        ));
      }
    }
    
    /* Methods */
    /**
     * Sets up the request
     * 
     * @param type The type of the request
     * @param unique TRUE if the request shall have a unique ID, FALSE otherwise
     */
    public function MediaRequest(type:String, unique:Boolean = false) {
      
      this._type = type;
      
      if (unique) {
        
        this._id = SHA1.hash((new Date().getTime()).toString());
      }
    }
    
    /**
     * Indicates that this request shall be cancelled
     */
    public function cancel():void {
      
      this.dispatchEvent(new Event(Event.CANCEL));
    }
  }
}