/* {{{ GPL

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

}}} */

var AnimationReader = Class.extend({
    
  // {{{ init
  init: function() {
  },
  // }}}
  
  // {{{ readAnimation
  readAnimation: function( pageName, versionNumber, onLoaded ) {
    this.ajaxRead( pageName, versionNumber, onLoaded, false );
  },
  // }}}

  // {{{ readFigure
  readFigure: function( pageName, versionNumber, onLoaded ) {
    this.ajaxRead( pageName, versionNumber, onLoaded, true );
  },
  // }}}
  
  // {{{ ajaxRead  
  ajaxRead: function( pageName, versionNumber, onLoaded, isFigure ) {

    var url = "/stickflick/raw/" + encodeURI( pageName ) + "?version=" + versionNumber;
    var ajax = Helpers.createAjax();
    var me = this;
    var isFig = isFigure;
    
    this.log.debug( "Reading animation/figure from", url, " Is figure?", isFig );
    
    ajax.onreadystatechange = function() {
      if ( ajax.readyState == 4 ) {
        if ( ajax.status == 200 ) {
          
          me.log.debug( "Read Response OK" );
          me.log.debug( ajax.responseText );
          
          if ( isFig ) {
            var figure = me.convertFigureDocument( ajax.responseText );
            onLoaded( figure );
          } else {
            var animation = me.convertAnimationDocument( ajax.responseText );
            animation.pageName = pageName;
            onLoaded( animation );
          }
          
        } else {
          me.log.error( "Server response not OK (not 200) :", ajax.status, ":", ajax.responseText );
        }
      }
    }

    ajax.open( "GET", url, true );
    ajax.send( null );
    
    this.log.debug( "Read request sent, awaiting reply" );

  },
  // }}}

  // {{{ convertAnimationDocument
  convertAnimationDocument: function( xml ) {
    this.log.trace( "convertAnimationDocument" );
    
    var xdocument = Helpers.createXMLParser( xml );
    var xanimation = xdocument.documentElement;
    this.log.debug( "version", this.getAttribute( xanimation, "version" ) );
    this.log.debug( "xdocument", xdocument, "xanimation", xanimation ); 
    var version = this.getVersion( xanimation );
    // MORE - check the version number
    
    return this.convertAnimation( xanimation );
  },
  // }}}
  
  // {{{ convertFigureDocument
  convertFigureDocument: function( xml ) {
    this.log.trace( "convertFigureDocument" );
    
    var xdocument = Helpers.createXMLParser( xml );
    var xfigure = xdocument.documentElement;
    var version = this.getVersion( xfigure );
    // MORE - check the version number
    
    return this.convertFigure( xfigure );
  },
  // }}}
  
  // {{{ getVersion
  getVersion: function( xtopLevel ) {
    this.log.trace( "getVersion" );
    var version = this.getFloatAttribute( xtopLevel, "version" );
    if ( version == null ) {
      return 0.0;
    } else {
      return version;
    }
  },
  // }}}
  
  // {{{ convertAnimation
  convertAnimation: function( xanimation ) {
    this.log.trace( "convertAnimation" );
    
    var width = this.getRequiredIntAttribute( xanimation, "width" );
    var height = this.getRequiredIntAttribute( xanimation, "height" );

    var animation = new Animation( width, height );
    
    animation.frameDuration = this.getIntAttribute( xanimation, "frameDuration", 200 );

    for ( var i = 0; i < xanimation.childNodes.length; i ++ ) {
      var xchild = xanimation.childNodes[ i ];
      
      if ( xchild.nodeName == "frame" ) {
        this.convertFrame( animation, xchild );
      }
      
      if ( xchild.nodeName == "figure" ) {
        var figure = this.convertFigure( xchild );
        animation.addFigure( figure );
      }

      if ( xchild.nodeName == "backgroundColor" ) {
        var color = this.convertColor( xchild );
        animation.backgroundColor = color;
      }
    }
    
    return animation;
  },
  // }}}
  
  // {{{ convertFrame
  convertFrame: function( animation, xframe ) {
    this.log.trace( "convertFrame" );
    
    var frame = new Frame();
    animation.addFrame( frame );
    this.log.debug( "Added frame. Camera view = ", frame.cameraView );
    
    for ( var i = 0; i < xframe.childNodes.length; i ++ ) {
      var xchild = xframe.childNodes[ i ];
      
      if ( xchild.nodeName == "figure" ) {
        var figure = this.convertFigure( xchild );
        frame.addFigure( figure );
      } else if ( xchild.nodeName == "camera" ) {
        this.convertCamera( animation, frame.cameraView, xchild );
        this.log.debug( "done cameraView? 0th figure : ", frame.figures[0] );
      }
    }

  },
  // }}}

  // {{{ convertCamera
  convertCamera: function( animation, cameraView, xcamera ) {
  
    var x = this.getRequiredFloatAttribute( xcamera, "x" );
    var y = this.getRequiredFloatAttribute( xcamera, "y" );
    var zoom = this.getRequiredFloatAttribute( xcamera, "zoom" );
    var angle = this.getRequiredFloatAttribute( xcamera, "angle" );
    
    this.log.debug( "camera", x, y, zoom, angle );
    
    cameraView.translate( x - animation.width / 2, y - animation.height / 2 );
    cameraView.scale( zoom );
    cameraView.rotate( angle );
    
    this.log.debug( "camera", cameraView );
  },
  // }}}
  
  // {{{ convertFigure
  convertFigure: function( xfigure ) {
    this.log.trace( "convertFigure" );
    
    var figure = new Figure();
    
    figure.name = this.getRequiredAttribute( xfigure, "name" );
    figure.id = this.getIntAttribute( xfigure, "id", 0 );
    
    xpalette = this.getRequiredElement( xfigure, "palette" );
    figure.palette = this.convertPalette( xpalette );
    
    xroot = this.getRequiredElement( xfigure, "root" );
    var root = this.convertNode( xroot );
    root.figure = figure;
    figure.root = root;

    return figure;
  },
  // }}}

  // {{{ convertPalette
  convertPalette: function( xpalette ) {
    this.log.trace( "convertPalette" );

    var palette = new Palette();
    
    for ( var i = 0; i < xpalette.childNodes.length; i ++ ) {
      var xchild = xpalette.childNodes[ i ];
      
      if ( xchild.nodeName == "color" ) {
        var color = this.convertColor( xchild );
        palette.addColor( color );
      }
    }
    
    return palette;
  },
  // }}}
  
  // {{{ convertColor
  convertColor: function( xcolor ) {
     this.log.trace( "convertColor" );
   
    var red = this.getRequiredFloatAttribute( xcolor, "red" );
    var green = this.getRequiredFloatAttribute( xcolor, "green" );
    var blue = this.getRequiredFloatAttribute( xcolor, "blue" );
    var alpha = this.getFloatAttribute( xcolor, "alpha", null );

    return Color.createFromFloats( red, green, blue, alpha );
    
  },
  // }}}
  
  // {{{ convertNode
  convertNode: function( xnode ) {
    this.log.trace( "convertNode" );
    
    var name = xnode.nodeName;
    var x = this.getRequiredFloatAttribute( xnode, "x" );
    var y = this.getRequiredFloatAttribute( xnode, "y" );
    
    var node;
    
    if ( name == "root" ) {
      node = new Root( x, y, null );
    } else if ( name == "line" ) {
      node = new Line( x, y );
    } else if ( name == "control" ) {
      node = new Control( x, y );
    } else if ( name == "ellipse" ) {
      node = new Ellipse( x, y );
    } else if ( name == "image" ) {
      node = new Line( x, y );
      node.lineWidth = 0;
    } else {
      throw "Unknow node tag : " + name;
    }
    
    if ( defined( node.lineWidth  ) ) {
      node.lineWidth = this.getFloatAttribute( xnode, "lineWidth", node.lineWidth );
    }
    node.lineColorIndex = this.getIntAttribute( xnode, "lineColor", null );
    node.fillColorIndex = this.getIntAttribute( xnode, "fillColor", null );
    node.isStatic = this.getBooleanAttribute( xnode, "static", false );

    var drawIndex = this.getIntAttribute( xnode, "drawIndex", -1 );
    //if ( drawIndex >= 0 ) {
    node.drawIndex = drawIndex;
    //}

    var behaviourName = this.getAttribute( xnode, "behaviour", null );
    if ( (behaviourName != null) && (node.changeBehaviour != null) ) {
      node.changeBehaviour( behaviourName );
    }

    for ( var i = 0; i < xnode.childNodes.length; i ++ ) {
      var xchild = xnode.childNodes[ i ];
      var nodeName = xchild.nodeName;
      
      if ( (nodeName == "line") || (nodeName == "ellipse") || (nodeName == "image") ) {
        
        var child = this.convertNode( xchild );
        node.addNode( child );
        child.clearControls();
        for ( var j = 0; j < xchild.childNodes.length; j ++ ) {
          var xgrandchild = xchild.childNodes[ j ];
          if ( xgrandchild.nodeName == "control" ) {
            child.addControl( this.convertNode( xgrandchild ) );
          }
        }
        
      }
    }
      
    return node;
  },
  // }}}
  
  
  // {{{ getRequiredElement
  getRequiredElement: function( xparent, name ) {
    var result = null;
    
    for ( var i = 0; i < xparent.childNodes.length; i ++ ) {
      var child = xparent.childNodes[ i ];
      
      document.foo = child;
      
      if ( child.nodeName == name ) {
        if (result != null) {
          throw "Only expected a single " + name + "tag.";
        }
        result = child;
      }
    }
    if ( result == null ) {
      throw "Tag " + name + " not found";
    }
    
    return result;
  },
  // }}}
  
  // {{{ getAttribute
  getAttribute: function( xelement, name, defaultValue ) {
    var value = xelement.getAttribute( name );
    if ( value == "" ) {
      value = null;
    }
    
    if ( (value == null) || (value == "") ) {
      if (defaultValue != null) {
        return defaultValue;
      }
      return null;
    }
    
    return value;
  },
  // }}}
  
  // {{{ getRequiredAttribute
  getRequiredAttribute: function( xelement, name ) {
    var value = xelement.getAttribute( name );
    if ( value == "" ) {
      value = null;
    }
    if ( value == null ) {
      throw "Required Attribute " + name + " not found";
    }
    return value;
  },
  // }}}
  
  // {{{ getRequiredIntAttribute
  getRequiredIntAttribute: function( xelement, name ) {
    var value = this.getRequiredAttribute( xelement, name );
    return parseInt( value );
  },
  // }}}
  
  // {{{ getIntAttribute
  getIntAttribute: function( xelement, name, defaultValue ) {
    var value = this.getAttribute( xelement, name, defaultValue );
    if ( value != null ) {
      return parseInt( value );
    } else {
      return defaultValue;
    }
  },
  // }}}
  
  // {{{ getRequiredFloatAttribute
  getRequiredFloatAttribute: function( xelement, name ) {
    var value = this.getRequiredAttribute( xelement, name );
    return parseFloat( value );
  },
  // }}}

  // {{{ getFloatAttribute
  getFloatAttribute: function( xelement, name, defaultValue ) {
    var value = this.getAttribute( xelement, name, defaultValue );
    if ( value != null ) {
      return parseFloat( value );
    } else {
      return null;
    }
  },
  // }}}
  
  
  // {{{ getBooleanAttribute
  getBooleanAttribute: function( xelement, name, defaultValue ) {
    var value = this.getAttribute( xelement, name );
    if ( value != null ) {
      return value.toUpperCase() == "TRUE";
    } else {
      return defaultValue;
    }
  },
  // }}}
      
  
});

AnimationReader.prototype.log = new Log( "AnimationReader" );



