package tdh.utils
{
   import flash.display.Bitmap;
   import flash.geom.Rectangle;
   import flash.display.BitmapData;
   import flash.utils.Dictionary;
   import flash.geom.Point;
   import flash.events.Event;
   import flash.utils.getTimer;
   import flash.display.MovieClip;
   
   public class BitmapClip extends Bitmap
   {
      
      public function BitmapClip(src:*, width:int = -1, height:int = -1, fps:int = 24)
      {
         var i:* = 0;
         var length:* = 0;
         var bmpd:BitmapData = null;
         var rect:Rectangle = null;
         this.list = new Vector.<BitmapData>();
         this.dict = new Dictionary();
         super();
         this.cutRect = new Rectangle(0,0,width,height);
         this.fps = fps;
         if(src is BitmapData)
         {
            width = src.width / Math.abs(width);
            height = src.height / Math.abs(height);
            this.bitmapData = src;
            this.gotoAndPlay(1);
         }
         else if(src is Vector.<BitmapData>)
         {
            length = src.length;
            i = 0;
            while(i < length)
            {
               this.bitmapData = src[i];
               i++;
            }
            this.gotoAndPlay(1);
         }
         else if(src is MovieClip)
         {
            rect = new Rectangle(0,0,width,height);
            length = src.totalFrames;
            i = 0;
            while(i < length)
            {
               src.gotoAndStop(i);
               bmpd = new BitmapData(width,height);
               bmpd.draw(src,null,null,null,rect);
               this.pushFrameBmp(bmpd);
               i++;
            }
         }
         
         
      }
      
      public var fps:int;
      
      private var _totalFrames:int;
      
      private var _currFrames:int;
      
      private var cutRect:Rectangle;
      
      private var list:Vector.<BitmapData>;
      
      private var dict:Dictionary;
      
      private var _playOnce:Boolean;
      
      private var _playOnceStartTime:int;
      
      private var _hideAfterOver:Boolean;
      
      public var setFrameIndex:int;
      
      override public function set bitmapData(value:BitmapData) : void
      {
         var bmpd:BitmapData = null;
         var x:* = 0;
         var dest:Point = new Point(0,0);
         var yLen:int = value.width / this.cutRect.width;
         var xLen:int = value.height / this.cutRect.height;
         var y:int = 0;
         while(y < yLen)
         {
            this.cutRect.y = this.cutRect.height * y;
            x = 0;
            while(x < xLen)
            {
               this.cutRect.x = this.cutRect.width * x;
               bmpd = new BitmapData(this.cutRect.width,this.cutRect.height);
               bmpd.copyPixels(value,this.cutRect,dest);
               this.pushFrameBmp(bmpd);
               x++;
            }
            y++;
         }
      }
      
      private function pushFrameBmp(bitmapData:BitmapData) : void
      {
         if(this.setFrameIndex < this.list.length)
         {
            this.list[this.setFrameIndex++] = bitmapData;
         }
         else
         {
            this.setFrameIndex = this._totalFrames = this.list.push(bitmapData);
         }
      }
      
      private function onFrame(e:Event) : void
      {
         if((visible == false) || (stage == null))
         {
            this.stop();
         }
         else if(this._playOnce)
         {
            this.playOnceOnFrame();
         }
         else
         {
            this.playOnFrame();
         }
         
      }
      
      private function playOnFrame() : void
      {
         var frame:int = getTimer() / (1000 / this.fps);
         var bl:BitmapClipLabel = this.dict[this._currentLabel];
         if(bl == null)
         {
            frame = frame % this._totalFrames;
         }
         else
         {
            frame = frame % (bl.to - bl.from) + bl.from;
         }
         super.bitmapData = this.list[this._currFrames = frame];
      }
      
      private var _currentLabel:String;
      
      public function register(label:String, from:uint, to:uint = 4.294967295E9) : void
      {
         var $label:BitmapClipLabel = null;
         $label = this.dict[label] = this.dict[label] || new BitmapClipLabel();
         $label.from = from;
         $label.to = Math.min(this._totalFrames,to);
      }
      
      public function play(label:String = null) : void
      {
         this._currentLabel = label;
         if(!hasEventListener(Event.ENTER_FRAME))
         {
            addEventListener(Event.ENTER_FRAME,this.onFrame);
         }
      }
      
      public function stop() : void
      {
         removeEventListener(Event.ENTER_FRAME,this.onFrame);
      }
      
      public function hideAndStop() : void
      {
         this.stop();
         visible = false;
      }
      
      public function showAndPlay() : void
      {
         this.play();
         visible = true;
      }
      
      public function gotoAndPlay(frame:int) : void
      {
         if((frame > 0) && (frame < this._totalFrames))
         {
            super.bitmapData = this.list[this._currFrames = frame - 1];
         }
         this.play();
      }
      
      public function gotoAndStop(frame:int) : void
      {
         if((frame > 0) && (frame < this._totalFrames))
         {
            super.bitmapData = this.list[this._currFrames = frame - 1];
         }
         this.stop();
      }
      
      public function nextFrame() : void
      {
         if(this._currFrames + 1 < this._totalFrames)
         {
            super.bitmapData = this.list[++this._currFrames];
         }
      }
      
      public function prevFrame() : void
      {
         if(this._currFrames - 1 > 0)
         {
            super.bitmapData = this.list[--this._currFrames];
         }
      }
      
      public function playOnce(hideAfterOver:Boolean = false, label:String = null) : void
      {
         this._currentLabel = label;
         this._playOnce = true;
         this._playOnceStartTime = getTimer();
         this._hideAfterOver = hideAfterOver;
         if(!hasEventListener(Event.ENTER_FRAME))
         {
            addEventListener(Event.ENTER_FRAME,this.onFrame);
         }
      }
      
      private function playOnceOnFrame() : void
      {
         var t:int = getTimer() - this._playOnceStartTime;
         var frame:int = int(t / (1000 / this.fps));
         var bl:BitmapClipLabel = this.dict[this._currentLabel];
         var totalFrames:int = this._totalFrames;
         if(bl != null)
         {
            totalFrames = bl.to;
            frame = frame + bl.from;
         }
         if(frame < totalFrames)
         {
            super.bitmapData = this.list[frame];
            this._currFrames = frame;
         }
         else
         {
            this._playOnce = false;
            if(this._hideAfterOver)
            {
               this.hideAndStop();
            }
            else
            {
               this.stop();
            }
            dispatchEvent(new Event(Event.COMPLETE));
         }
      }
      
      public function dispose() : void
      {
         var bmpd:BitmapData = null;
         for each(bmpd in this.list)
         {
            bmpd.dispose();
         }
         this.list.splice(0,this._totalFrames);
         this._totalFrames = this._currFrames = 0;
      }
   }
}
class BitmapClipLabel extends Object
{
   
   function BitmapClipLabel()
   {
      super();
   }
   
   public var from:int;
   
   public var to:int;
}
