
var Try = {
  these: function() {
    var returnValue;

    for (var i = 0, length = arguments.length; i < length; i++) {
      var lambda = arguments[i];
      try {
        returnValue = lambda();
        break;
      } catch (e) {}
    }
    return returnValue;
  }
}

function newConn() {
  return Try.these(
    function() {return new XMLHttpRequest()},
    function() {return new ActiveXObject('Msxml2.XMLHTTP')},
    function() {return new ActiveXObject('Microsoft.XMLHTTP')}
  ) || false;
}

function doConnStateChange(){
  for (var i=0; i<conns.length; ++i){
    if (conns[i].conn.readyState == 4){
      if (conns[i].conn.status == 200){
        if (typeof conns[i].callback != 'undefined')
          conns[i].callback(conns[i].conn.responseText,conns[i].url);
      }
      conns.splice(i,1); --i;
    }
  }
}

var conns=new Array();

function connGet(_url,_callback){
  if (document.location.href.substr(0,4)=="file"){ lerror("local documents cannot listen on connections"); return; }
  var sconn;
  try {
    sconn = {conn: newConn(), callback: _callback, url: _url };
    if (sconn.conn===false){ lerror("unable to create connection"); return; }
    conns[conns.length]=sconn;
    sconn.conn.onreadystatechange = doConnStateChange;
    sconn.conn.open("GET",_url,true);
    sconn.conn.send("");
  } catch(e) {
    lerror("unable to setup connection");
  }
}

function connPost(_url,_data,_callback){
  if (document.location.href.substr(0,4)=="file"){ lerror("local documents cannot listen on connections"); return; }
  var sconn;
  try {
    sconn = {conn: newConn(), callback: _callback, url: _url };
    if (sconn.conn===false){ lerror("Unable to create connection"); return; }
    conns[conns.length]=sconn;
    sconn.conn.onreadystatechange = doConnStateChange;
    sconn.conn.open("POST",_url,true);

    sconn.conn.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    sconn.conn.setRequestHeader("Content-length", _data.length);
    sconn.conn.setRequestHeader("Connection", "close");

    sconn.conn.send(_data);
  } catch(e) {
    lerror("unable to setup connection");
  }
}

var listenConn=null;

function doConnListenStateChange(){
  if (listenConn.conn.readyState == 4){
    if (listenConn.conn.status == 200)
      listenConn.callback(listenConn.conn.responseText,listenConn.url);

    if (listenConn.conn.status != 0 && listenConn.conn.status != 404 && listenConn.conn.status != 12029){
      if (listenConn.conn.status != 200) 
        linfo("connection info, listenConn.status="+listenConn.conn.status);
      connListen(listenConn.callback);
    } else {
      lerror("connection failed, listenConn.status="+listenConn.conn.status);
    }
  }
}

function connListen(_callback){
  if (typeof _callback == 'undefined'){ lerror("undefined callback in connListen()"); return; }
  if (document.location.href.substr(0,4)=="file"){ lerror("local documents cannot listen on connections"); return; }

  var dte=new Date();

  try {
    listenConn = {conn: newConn(), callback: _callback, url: "/server.php?"+dte.valueOf()+"&sid="+sid+"&channel="+channel };
    if (listenConn.conn===false){ lerror("unable to create connection"); return; }
    listenConn.conn.onreadystatechange = doConnListenStateChange;
    listenConn.conn.open("GET","/server.php?"+dte.valueOf()+"&sid="+sid+"&channel="+channel,true);
    listenConn.conn.send("");
  } catch(e) {
    lerror("unable to setup listening connection: "+e);
  }
}


var sendConnections=0;
var sendConns=new Array();
var sendBuffer="";

function doConnSendStateChange(){
  for (var i=0; i<sendConns.length; ++i){
    if (sendConns[i].conn.readyState == 4){
/*
      if (sendConns[i].conn.status == 200){
        sendConns[i].callback(sendConns[i].conn.responseText,sendConns[i].url);
      }
*/
      --sendConnections;
      if (sendConns[i].conn.status != 200)
        connResendData(sendConns[i].data);
      sendConns.splice(i,1); --i;
    }
  }
  if (sendConnections<=1 && sendBuffer.length>0){
    ++sendConnections;
    connSendData();
  }
}

function connSendData(){
  if (sendBuffer.length==0) return;

  var sconn;
  var dte=new Date();

  try {
    sconn = {conn: newConn(), url: "/server.php?"+dte.valueOf()+"&sid="+sid+"&channel="+channel, data: sendBuffer };
    if (sconn.conn===false){ lerror("unable to create connection"); return; }
    sendConns[sendConns.length]=sconn;
    sconn.conn.onreadystatechange = doConnSendStateChange;
    sconn.conn.open("POST","/server.php?"+dte.valueOf()+"&sid="+sid+"&channel="+channel,true);
    sconn.conn.send(sendBuffer);
    sendBuffer="";
  } catch(e) {
    --sendConnections;
    lerror("DEVELTODO: look for connection to delete! unable to setup connection");
  }
}

function connResend(_data){
  lwarn("got error sending data (retrying): "+_data);

  if (sendBuffer.length>0)
    sendBuffer+=_data+";";
  else
    sendBuffer=_data;

  if (sendConnections<=1){
    ++sendConnections;
    connSendData();
//    setTimeout("connSendData();",25);
  }
}

function connSend(_data){
  if (document.location.href.substr(0,4)=="file"){ lerror("local documents cannot listen on connections"); return; }

  if (sendBuffer.length>0)
    sendBuffer+=";"+_data;
  else
    sendBuffer=_data;

  if (sendConnections<=1){
    ++sendConnections;
    setTimeout("connSendData();",25);
  }
}


function connStatus(_callback){
  var dte=new Date();
  connGet("/status.php?"+dte.valueOf()+"&sid="+sid+"&channel="+channel,_callback);
}





function cactordefs(){
  
}

function serialize(obj){
  var str="";
  var i;
  switch(typeof obj){
    case 'string':
      str+='"'+obj+'"';
     break;
    case 'number':
      str+=obj;
     break;
    case 'array':
      str+="{";
      for (i=0; i<obj.length; ++i)  
        str+=i+":"+serialize(obj[i])+",";
      for (i in obj)
        str+=i+":"+serialize(obj[i])+",";
      if (str.length>1)
        str=str.substr(0,str.length-1)+"}";
      else
        str+="}";
     break;
    case 'object':
      str+="{";
      for (i in obj)
        str+=i+":"+serialize(obj[i])+",";
      if (str.length>1)
        str=str.substr(0,str.length-1)+"}";
      else
        str+="}";
     break;
    case 'boolean':
      if (obj) str+='true';
      else str+='false';
     break;
    default:
      alert("serialize: unhandled type: "+typeof obj);
  }
  return(str);
}

function savedActordefData(data){
  alert("Actor action saved!");
//  if (data.length>0)
//    alert(data);
}

cactordefs.prototype.save=function(actor,action){
  if (!(actor in actordefs)) return;

  if (!(action in actordefs[actor].actions)) return;
  
  var scale=actordefs[actor].scale;

  var framedata=serialize(actordefs[actor].actions[action]);
//  alert(framedata);

  connPost("/actordefs.php?actor="+actor+"&action="+action+"&scale="+scale,framedata,savedActordefData);
}

actordef=new cactordefs;



function vector(x,y){
  if (typeof x == 'undefined'){
    this.x=0; this.y=0;
    return;
  }
  this.x=x; this.y=y;
}



function getActorDir(a1){
  var actorVer=0;
  if (typeof actordefs[a1].version != 'undefined')
    actorVer=actordefs[a1].version;
  return("/actors-"+actorsVer+"/"+a1+"-"+actorVer);
}

function cimages(){
  this.imgsList={};
  this.imgsCount=0;
  this.loadingCount=0;
  this.loading=false;
  this.onLoaded={};
  this.onLoadedCount=0;
  this.onLoadedAdd=function(callback){ images.onLoaded[images.onLoadedCount]=callback; images.onLoadedCount++; return(images.onLoadedCount-1); }

  this.callbackDoImageLoaded=objCallback(this,"doImageLoaded");
  this.callbackDoImageLoadError=objCallback(this,"doImageLoadError"); 
}


cimages.prototype.doImageLoadError=function(){
  lerror("error loading: "+this.src + " --- " +this.complete);
}

//cimages.prototype.onLoaded=function(){} //should be implemented by other objects

cimages.prototype.doImageLoaded=function(){
  ++this.loadingCount;
  if (this.loadingCount==this.imgsCount){
    for (i in this.onLoaded)
      this.onLoaded[i]();
    this.loading=false;
  }
/*
  if (this.loading){
    if (!movieLoaded){
    
    }else if (!startLoading && this.loadingCount==this.imgsCount){
      this.loading=false;
      hideLoading();
      playMovie();
      update();
    }else{
      movieControl=0;
      showLoading();
    }
  }else{
//    alert(loadingCount + " , "+imgsCount);
    if (!startLoading && this.loadingCount==this.imgsCount && scene==""){
      loadRandomScene();
    }
  }
*/
//  if (typeof callback != 'undefined')
//    callback();
}

cimages.prototype.load=function(name,url){
  if (name in this.imgsList) { return; }

  ++this.imgsCount;
  this.loading=true;
  this.imgsList[name] = new Image();

  this.imgsList[name].onload=this.callbackDoImageLoaded;
  if (IE)
    this.imgsList[name].onerror=this.callbackDoImageLoadError;
  this.imgsList[name].src=url;
}

cimages.prototype.loadImgOnly=function(imgsList,a,b){
  if (a in imgsList)
    this.load(a,b);
}

cimages.prototype.loadOnlyActorActions=function(imgsList,a1){
  var a2;
  for (a2 in actordefs[a1].actions){
    if (a2 == "indexOf") continue;
    if (actordefs[a1].actions[a2].frames==0){
      this.loadImgOnly(imgsList,a1+"-"+a2+"--1",getActorDir(a1)+"/"+a1+"-"+a2+".png");
      this.loadImgOnly(imgsList,a1+"-"+a2+"-1",getActorDir(a1)+"/rev-"+a1+"-"+a2+".png");
    }else{
      for (var i=0; i<actordefs[a1].actions[a2].frames; i++){
        this.loadImgOnly(imgsList,a1+"-"+a2+"-"+i+"--1",getActorDir(a1)+"/"+a1+"-"+a2+"-"+i+".png");
        this.loadImgOnly(imgsList,a1+"-"+a2+"-"+i+"-1",getActorDir(a1)+"/rev-"+a1+"-"+a2+"-"+i+".png");
      }
    }
  }
}

cimages.prototype.loadOnly=function(imgsList){
  var a1;
  var a2;
  for (a1 in actordefs){
    if (a1 == "indexOf") continue;
    this.loadOnlyActorActions(imgsList,a1);
  }
}

cimages.prototype.loadAll=function(){
  var a1;
  var a2;
  for (a1 in actordefs){
    if (a1 == "indexOf") continue;
    this.loadActorActions(a1);

    a2="stand";
    if (a2 in actordefs[a1].actions){
      if (a2 == "indexOf") continue;
      this.loadActorAction(a1,a2);
    }
  }
}

cimages.prototype.loadActor=function(a1){
  var a2="stand";
  if (a2 in actordefs[a1].actions){
    if (a2 == "indexOf") return;
      
    if (actordefs[a1].actions[a2].frames==0){
      this.load(a1+"-"+a2+"--1",getActorDir(a1)+"/"+a1+"-"+a2+".png");
//      loadImage(a1+"-"+a2+"-1",getActorDir(a1)+"/rev-"+a1+"-"+a2+".png");
    }else{
      this.load(a1+"-"+a2+"-0--1",getActorDir(a1)+"/"+a1+"-"+a2+"-0.png");
//      loadImage(a1+"-"+a2+"-1",getActorDir(a1)+"/rev-"+a1+"-"+a2+"-0.png");      
    }
  }
}

cimages.prototype.loadActors=function(){
  var a1;
  for (a1 in actordefs){
    if (a1 == "indexOf") continue;
    this.loadActor(a1);
  }
}

cimages.prototype.loadActorActions=function(a1){
  var a2;
  for (a2 in actordefs[a1].actions){
    if (a2 == "indexOf") continue;
    if (actordefs[a1].actions[a2].frames==0){
      this.load("action-"+a1+"-"+a2,getActorDir(a1)+"/action-"+a1+"-"+a2+".png");
      this.load(a1+"-"+a2+"--1",getActorDir(a1)+"/"+a1+"-"+a2+".png");
      this.load(a1+"-"+a2+"-1",getActorDir(a1)+"/rev-"+a1+"-"+a2+".png");
    }else{
      var i=0;
      if (i<actordefs[a1].actions[a2].frames){
        this.load("action-"+a1+"-"+a2,getActorDir(a1)+"/action-"+a1+"-"+a2+"-"+i+".png");
        this.load(a1+"-"+a2+"-"+i+"--1",getActorDir(a1)+"/"+a1+"-"+a2+"-"+i+".png");
        this.load(a1+"-"+a2+"-"+i+"-1",getActorDir(a1)+"/rev-"+a1+"-"+a2+"-"+i+".png");
      }
    }
  }
}

cimages.prototype.loadActorAction=function(a1,a2){
  for (var i=0; i<actordefs[a1].actions[a2].frames; ++i){
    if (typeof actordefs[a1].actions[a2].framedefs != 'undefined' && typeof actordefs[a1].actions[a2].framedefs[i].img != 'undefined') continue;
    this.load(a1+"-"+a2+"-"+i+"-1",getActorDir(a1)+"/rev-"+a1+"-"+a2+"-"+i+".png");
    this.load(a1+"-"+a2+"-"+i+"--1",getActorDir(a1)+"/"+a1+"-"+a2+"-"+i+".png");
  }
}



function loadActorActionImgs(a1,a2,a3){
  if (actordefs[a1].actions[a2].frames==0){
    if (a3=="1")
      loadImage(a1+"-"+a2+"-1",getActorDir(a1)+"/rev-"+a1+"-"+a2+".png");
    else
      loadImage(a1+"-"+a2+"--1",getActorDir(a1)+"/"+a1+"-"+a2+".png");
  }else{
    for (var i=0; i<actordefs[a1].actions[a2].frames; ++i){
      if (a3=="1")
        loadImage(a1+"-"+a2+"-"+i+"-1",getActorDir(a1)+"/rev-"+a1+"-"+a2+"-"+i+".png");
      else
        loadImage(a1+"-"+a2+"-"+i+"--1",getActorDir(a1)+"/"+a1+"-"+a2+"-"+i+".png");
    }
  }
}

function loadOrderActorImages(){
  for (var i in loadOrder){
    if (i == "indexOf") continue;
    var tmp=i.split(".");
    loadActorActionImgs(tmp[0],tmp[1],tmp[2]);
  }  
}

function loadActorStandImages(){
  var a1;
  var a2;
  for (a1 in actordefs){
    if (a1 == "indexOf") continue;
    a2="stand";
    if (a2 in actordefs[a1].actions){
      if (a2 == "indexOf") continue;
      
      if (actordefs[a1].actions[a2].frames==-1){
        loadImage(a1+"-"+a2+"--1",getActorDir(a1)+"/"+a1+"-"+a2+".png");
//        loadImage(a1+"-"+a2+"-1",getActorDir(a1)+"/rev-"+a1+"-"+a2+".png");
      }else{
        loadImage(a1+"-"+a2+"--1",getActorDir(a1)+"/"+a1+"-"+a2+"-0.png");
//        loadImage(a1+"-"+a2+"-1",getActorDir(a1)+"/rev-"+a1+"-"+a2+"-0.png");      
      }
    }
  }
}

function loadActor1ActionImg(a1,a2){
  if (actordefs[a1].actions[a2].frames==-1){
    loadImage(a1+"-"+a2+"--1",getActorDir(a1)+"/"+a1+"-"+a2+".png");
    loadImage(a1+"-"+a2+"-1",getActorDir(a1)+"/rev-"+a1+"-"+a2+".png");
  }else{
    var i=0; 
    if (i<actordefs[a1].actions[a2].frames){
      loadImage(a1+"-"+a2+"-"+i+"--1",getActorDir(a1)+"/"+a1+"-"+a2+"-"+i+".png");
      loadImage(a1+"-"+a2+"-"+i+"-1",getActorDir(a1)+"/rev-"+a1+"-"+a2+"-"+i+".png");
    }
  }
}


function loadActorAll1Images(a1){
  var a2;
  for (a2 in actordefs[a1].actions){
    if (a2 == "indexOf") continue;
    if (actordefs[a1].actions[a2].frames==-1){
      loadImage("action-"+a1+"-"+a2,getActorDir(a1)+"/action-"+a1+"-"+a2+".png");
      loadImage(a1+"-"+a2+"--1",getActorDir(a1)+"/"+a1+"-"+a2+".png");
      loadImage(a1+"-"+a2+"-1",getActorDir(a1)+"/rev-"+a1+"-"+a2+".png");
    }else{
      var i=0;
      if (i<actordefs[a1].actions[a2].frames){
        loadImage("action-"+a1+"-"+a2,getActorDir(a1)+"/action-"+a1+"-"+a2+"-"+i+".png");
        loadImage(a1+"-"+a2+"-"+i+"--1",getActorDir(a1)+"/"+a1+"-"+a2+"-"+i+".png");
        loadImage(a1+"-"+a2+"-"+i+"-1",getActorDir(a1)+"/rev-"+a1+"-"+a2+"-"+i+".png");
      }
    }
  }
}

function loadActorAllImages(){
  var a1;
  var a2;
  for (a1 in actordefs){
    if (a1 == "indexOf") continue;

    for (a2 in actordefs[a1].actions){
      if (a2 == "indexOf") continue;
      if (actordefs[a1].actions[a2].frames==-1){
        loadImage(a1+"-"+a2+"--1",getActorDir(a1)+"/"+a1+"-"+a2+".png");
        loadImage(a1+"-"+a2+"-1",getActorDir(a1)+"/rev-"+a1+"-"+a2+".png");
      }else{
        for (var i=0; i<actordefs[a1].actions[a2].frames; ++i){
          loadImage(a1+"-"+a2+"-"+i+"--1",getActorDir(a1)+"/"+a1+"-"+a2+"-"+i+".png");
          loadImage(a1+"-"+a2+"-"+i+"-1",getActorDir(a1)+"/rev-"+a1+"-"+a2+"-"+i+".png");
        }
      }
    }
  }
}


var IE=0;
var IEPNGcorr=0;
var sWidth=640;
var sHeight=480;

function setHLBGColor(tag){
  this.style.backgroundColor="#ddf";
}
function setBGColor(tag){
  this.style.backgroundColor="#fff";
}
function setSBGColor(tag){
  this.style.backgroundColor="#fdd";
}

function createActionTag(action,tag,selected){
  var div;
  var img;
  div=document.createElement("div");

  if (typeof tag == 'undefined')
    document.body.appendChild(div);
  else
    tag.appendChild(div);

  var txt;
  txt=document.createElement("small");
  div.appendChild(txt);
  txt.innerHTML=action;

  if (IEPNGcorr){
    img=document.createElement("span");
    div.appendChild(img);
    img.style.display='inline';
  }else{
    img = document.createElement("img");
    div.appendChild(img);
  }

  if (typeof tag == 'undefined'){
    div.style.position="absolute";
    div.style.left=(sHeight/2)+"px";
    div.style.top=(sWidth/2)+"px";
  }
  div.style.padding="5px 5px 5px 5px"
//  div.style.marginBottom="4px";
  div.img=img;
  div.onmouseover=setHLBGColor;
  div.onmouseout=setBGColor;
  if (typeof selected != 'undefined' && selected){
    div.onmouseout=setSBGColor;
    div.style.backgroundColor="#fdd";
  }
  return(div);
}


/*
  // implement mirrored images (instead of downloading mirrored and)

<script type="text/javascript">

(function (element, event, handler) {
 if (element.addEventListener)
  element.addEventListener(event, handler, false);
 else if (element.attachEvent)
  element.attachEvent('on' + event, handler);
 else
  element['on' + event] = handler;
})(window, 'load', function () {
 document.img = (function (id, src, width, height) {
  var _element = document.getElementById(id);
  var _canvas = document.createElement('canvas');
  if (_canvas.getContext) {
   // Opera/Safari/FireFox code:
   _element.appendChild(_canvas);
   _canvas.setAttribute('width', width);
   _canvas.setAttribute('height', height);
   var _center = { 'x' : Math.round(width / 2), 'y' : Math.round(height / 2) };
   var _ctx = _canvas.getContext('2d');
   var _img = new Image();
   _img.onload = function () {
    _ctx.translate(_center.x, _center.y);
    _ctx.drawImage(_img, -1 * _center.x, -1 * _center.y);
   };
   _img.src = src;
   return {
    'rotateCW' : function () {
     _ctx.rotate(Math.PI/2);
     _ctx.drawImage(_img, -1 * _center.x, -1 * _center.y);
    },
    'rotateCCW' : function () {
     _ctx.rotate(-Math.PI/2);
     _ctx.drawImage(_img, -1 * _center.x, -1 * _center.y);
    }
   };
  }
  // IE code:
  var _rotation = 0;
  var _filter = 'progid:DXImageTransform.Microsoft.BasicImage(rotation={0})';
  _element.style.width = width + 'px';
  _element.style.height = height + 'px';
  _element.style.background = 'url(\'' + src + '\')';
  _element.style.backgroundPosition = 'center center';
  _element.style.backgroundRepeat = 'no-repeat';
  return {
   'rotateCW' : function () {
    _rotation = (_rotation + 1) % 4;
    _element.style.filter = _filter.replace('{0}', _rotation);
   },
   'rotateCCW' : function () {
    _rotation = (4 + _rotation - 1) % 4;
    _element.style.filter = _filter.replace('{0}', _rotation);
   }
  };
 })('image', '/files/n152.sample.png', 150, 150);
});
</script>
<button onclick="document.img.rotateCCW()" style="font-family: arial;">&#8592;</button>&nbsp;
<button onclick="document.img.rotateCW()" style="font-family: arial;">&#8594;</button>
<div id="image" style="margin: 1em;"></div>


*/



function createActorTag(){
  var img;
  if (IEPNGcorr){
    img = document.createElement("span");
    document.body.appendChild(img);
    img.style.display='inline';
  }else{
    img = document.createElement("img");
    document.body.appendChild(img);
  }
  img.style.position="absolute";
  return(img);
}


function actor(anim,type){
  this.anim=anim;
  this.x=0.5;
  this.y=0.5;
  this.type=type;
  this.fixed=false;
  this.action="stand";
  this.frame=0;
  this.direction=-1;

  this.z=0;
  this.scale=1.0;
  if (typeof actordefs[type] != 'undefined'){
    this.scale=actordefs[type].scale;
    if (typeof actordefs[type].zindex != 'undefined')
    this.z=actordefs[type].zindex;
  }
  this.attached=-1;
  this.vAttachedPos=new vector;
  this.showingOptions=false;

  this.menuLeft=0;
  this.menuTop=0;
  this.menuRight=0;
  this.menuBottom=0;

  this.changes={};

  this.tag=createActorTag();
  this.tag.style.left=(anim.vScale.x/2)+"px";
  this.tag.style.top=(anim.vScale.y/2)+"px";
/*
  this.tag=document.createElement(tag.tagName);
  document.body.appendChild(this.tag);
  this.tag.innerHTML=tag.innerHTML;
  this.tag.style.position="absolute";
  this.tag.style.left=tag.offsetLeft+"px";
  this.tag.style.top=tag.offsetTop+"px";
  this.tag.style.top=(2*tag.offsetTop-this.tag.offsetTop)+"px";
  this.x=parseInt(this.tag.style.left)/this.anim.vScale.x;
  this.y=parseInt(this.tag.style.top)/this.anim.vScale.y;
  tag.style.visibility="hidden";
*/

  this.tag.actor=this;
  this.tag.ondragstart=function(){ return(false); }
  this.tag.onselectstart=function(){ return(false); }
  this.tag.onmousedown=function(){ return(false); }

  this.mouseMoveHandlerHideOptions=objCallback(this,"checkHideOptions");
  this.mouseMoveHandler=objCallback(this,"doMouseMove");
  this.mouseUpHandler=objCallback(this,"doMouseUp");
  this.resizeMouseMoveHandler=objCallback(this,"doResizeMouseMove");
  this.resizeMouseUpHandler=objCallback(this,"doResizeMouseUp");

  this.draw();
}


actor.prototype.update=function(forward){
  var timeStep=1;
//  if (!forward)
//    timeStep=-1

  var action=actordefs[this.type].actions[this.action];
  
  if ("framedefs" in action){
    if (typeof action.framedefs[this.frame].sound != 'undefined'){
      this.anim.sound.play(action.framedefs[this.frame].sound);
    }
    if (!this.fixed){
      this.x -= timeStep*this.scale*this.direction*action.framedefs[this.frame].dx/1000.0;
      this.y += timeStep*this.scale*action.framedefs[this.frame].dy/1000.0;
    }
  }

  if (action.frames==0)
    this.frame=0;
  else{
    if (this.frame+timeStep<action.frames){
      this.frame=this.frame+timeStep; 
    } else if (this.frame+timeStep==action.frames && ((typeof action.aloop=="number" && action.aloop!=-1) || (typeof action.aloop=="boolean" && action.aloop==true))){
      if (typeof action.aloop=="boolean")
        this.frame=0;
      else
        this.frame=action.aloop;
    } else if (this.frame+timeStep==action.frames && typeof action.aend != 'undefined') {
      if (action.aend.substr(0,6)=="action"){
        this.frame=0; this.action=action.aend.substr(7,action.aend.length-7);
      }else if (action.aend=="delete"){
        this.anim.deleteActor(this.anim.getActorIndex(this));
	return;
      }
    }
  }
}

actor.prototype.setEditable=function(){
  this.tag.onmousedown=function(e){ return(this.actor.doMouseDown(e)); }
  this.tag.onmouseover=function(e){ return(this.actor.showOptions(e)); }
}

var dragActor=null;

actor.prototype.doMouseDown=function(e){
  e = e || window.event;
  dragActor=this;
  this.startDragX=e.clientX;
  this.startDragY=e.clientY;
  this.startX=this.x;
  this.startY=this.y;

  addEvent(document, 'mousemove', this.mouseMoveHandler, false);
  addEvent(document, 'mouseup', this.mouseUpHandler, false);
  return(false);
}
actor.prototype.doMouseMove=function(e){
  e = e || window.event;
  this.x = this.startX + (e.clientX-this.startDragX)/this.anim.vScale.x;
  this.y = this.startY + (e.clientY-this.startDragY)/this.anim.vScale.y;
  this.tag.style.left = (this.anim.vRefpos.x + this.x*this.anim.vScale.x - this.tag.offsetWidth/2)+"px";
  this.tag.style.top = (this.anim.vRefpos.y + this.y*this.anim.vScale.y - this.tag.offsetHeight/2)+"px";
  this.moveOptions();
  return(false);
}
actor.prototype.doMouseUp=function(e){
  this.changes.x=this.x;
  this.changes.y=this.y;
  removeEvent(document, 'mousemove', this.mouseMoveHandler, false);
  removeEvent(document, 'mouseup', this.mouseUpHandler, false);
  return(false);
}


actor.prototype.doResizeMouseDown=function(e){
  e = e || window.event;
  resizeActor=this;
  this.startX=e.clientX;
  this.startY=e.clientY;
  this.startScale=this.scale;
  this.startResizeX=this.tag.offsetWidth;
  this.startResizeY=this.tag.offsetHeight;

  addEvent(document, 'mousemove', this.resizeMouseMoveHandler, false);
  addEvent(document, 'mouseup', this.resizeMouseUpHandler, false);
  return(false);
}
actor.prototype.doResizeMouseMove=function(e){ 
  var scaleX = (this.tag.owidth*this.startScale + 2.0*(e.clientX-this.startX))/this.tag.owidth;
  var scaleY = (this.tag.oheight*this.startScale + 2.0*(e.clientY-this.startY))/this.tag.oheight;
  
//  var scaleX = (this.startResizeX + e.clientX-this.startX)/this.startResizeX;
//  var scaleY = (this.startResizeY + e.clientY-this.startY)/this.startResizeY;

  this.scale = (scaleX < scaleY ? scaleY : scaleX);

//  this.tag.style.width = Math.floor(this.scale*this.startResizeX)+"px";
//  this.tag.style.height = Math.floor(this.scale*this.startResizeY)+"px";
  this.tag.style.width = Math.floor(this.scale*this.tag.owidth*this.anim.vScale.x/800.0)+"px";
  this.tag.style.height = Math.floor(this.scale*this.tag.oheight*this.anim.vScale.x/800.0)+"px";
  this.tag.style.left = (this.anim.vRefpos.x + this.x*this.anim.vScale.x - this.tag.offsetWidth/2)+"px";
  this.tag.style.top = (this.anim.vRefpos.y + this.y*this.anim.vScale.y - this.tag.offsetHeight/2)+"px";
  this.moveOptions();
  return(false);
}
actor.prototype.doResizeMouseUp=function(e){
  this.changes.scale=this.scale;
  removeEvent(document, 'mousemove', this.resizeMouseMoveHandler, false);
  removeEvent(document, 'mouseup', this.resizeMouseUpHandler, false);
  return(false);
}




function getActionLabel(type,action){
  if (typeof actorlabels != 'undefined' && typeof actorlabels[type] != 'undefined' && typeof actorlabels[type].actions[action] != 'undefined')
    return(actorlabels[type].actions[action]);
  return(action);
}


function getActorImage(_actor,_action,_frame,_direction){
  var imgname;
  if (typeof _direction == 'undefined') _direction=-1;
  if (typeof _frame == 'undefined') _frame=0;
  
  if (actordefs[_actor].actions[_action].frames!=0)
    imgname=_actor+"-"+_action+"-"+_frame;
  else
    imgname=_actor+"-"+_action;
  return(imgname);  
}

actor.prototype.moveOptions=function(){
  if (!this.showingOptions) return;

  this.menuDelete.style.left = (this.tag.offsetLeft+this.tag.offsetWidth-12)+"px";
  this.menuDelete.style.top = (this.tag.offsetTop-12)+"px";

  this.menuTop=12;
  this.menuRight=this.menuDelete.offsetWidth;

  this.menuDir.style.left = (this.tag.offsetLeft+this.tag.offsetWidth/2-12)+"px";
  this.menuDir.style.top = (this.tag.offsetTop+this.tag.offsetHeight)+"px";
  this.menuBottom=this.menuDir.offsetHeight;

  this.menuResize.style.left = (this.tag.offsetLeft+this.tag.offsetWidth)+"px";
  this.menuResize.style.top = (this.tag.offsetTop+this.tag.offsetHeight)+"px";
//  this.menuBottom=this.menuDir.offsetHeight;


  this.menuActions.tag.style.left = (this.tag.offsetLeft-this.menuActions.tag.offsetWidth)+"px"; 
  this.menuActions.tag.style.top = (this.tag.offsetTop-12)+"px";
  if (this.menuBottom < this.menuActions.tag.offsetHeight-this.tag.offsetHeight-12)
    this.menuBottom=this.menuActions.tag.offsetHeight-this.tag.offsetHeight-12;

  this.menuLeft=this.menuActions.tag.offsetWidth;

/*
  this.menuLeft=0;
  for (var i=0; i<this.menuActions.length; ++i){
    var actionItem=this.menuActions[i];
    if (actionItem.offsetWidth>this.menuLeft)this.menuLeft=actionItem.offsetWidth;
    actionItem.style.left = (this.tag.offsetLeft-actionItem.offsetWidth)+"px";
    actionItem.style.top = (this.tag.offsetTop-12 + i*24)+"px";
  }
*/
}

var optionActor=null;

actor.prototype.checkHideOptions=function(e){
  e = e || window.event;
  if (typeof window.pageYOffset == 'undefined') window.pageYOffset = document.body.scrollTop;
  if (typeof window.pageXOffset == 'undefined') window.pageXOffset = document.body.scrollLeft;

  if (window.pageXOffset+e.clientX < this.tag.offsetLeft-this.menuLeft-5 || window.pageXOffset+e.clientX > this.tag.offsetLeft+this.tag.offsetWidth+this.menuRight+5 ||
      window.pageYOffset+e.clientY < this.tag.offsetTop-this.menuTop-5 || window.pageYOffset+e.clientY > this.tag.offsetTop+this.tag.offsetHeight+this.menuBottom+5)
    this.hideOptions();
}

actor.prototype.showOptions=function(e){
  if (this.showingOptions) return;

  if (optionActor!=null) optionActor.hideOptions();
  optionActor=this;

  this.showingOptions=true;
  this.tag.style.zIndex=100;
  this.menuDelete = createActorTag();
  this.menuDelete.actor=this;
  this.menuDelete.src="/imgs/actor-delete.png";
  this.menuDelete.style.zIndex=101;
  this.menuDelete.onmousedown=function(){ this.actor.anim.deleteActor(this.actor.index); }
  this.menuDir = createActorTag();
  this.menuDir.actor=this;
  this.menuDir.src="/imgs/actor-direction.png";
  this.menuDir.style.zIndex=101;
  this.menuDir.onmousedown=function(){ this.actor.changeDirection(); }
  this.menuResize = createActorTag();
  this.menuResize.actor=this;
  this.menuResize.src="/imgs/actor-resize.png";
  this.menuResize.style.zIndex=101;
//  this.menuResize.onmousedown=function(){ this.actor.changeSize(); }
  this.menuResize.onmousedown=function(e){ return(this.actor.doResizeMouseDown(e)); }


  this.menuActions=new Array();
  var menuActionsTag = document.createElement("div");
  this.menuActions.tag=menuActionsTag;
  document.body.appendChild(menuActionsTag);
  menuActionsTag.style.position="absolute";
  menuActionsTag.style.backgroundColor="#fff";
  menuActionsTag.style.textAlign="right";
//  menuActions.style.padding="5px 5px 5px 5px";
  menuActionsTag.style.border="1px solid #333";
  menuActionsTag.style.padding="5px 5px 5px 5px";
  menuActionsTag.style.zIndex="1010";
  menuActionsTag.actor=this;

  var i=0;
  for (var a in actordefs[this.type].actions){
    var label=getActionLabel(this.type,a);
   
    var newAction=createActionTag(label,menuActionsTag,a==this.action);
    if (a==this.action)
      this.menuActions.selected=newAction;

    newAction.actor=this;
    newAction.action=a;
    newAction.img.src=getActorDir(this.type)+"/action-"+getActorImage(this.type,a)+".png";
    newAction.img.style.verticalAlign="middle";
    newAction.style.zIndex=101;
    newAction.onmousedown=function(){ this.actor.anim.nextTutorial('action'); this.actor.changeAction(this.action); }
    this.menuActions[this.menuActions.length]=newAction;
    i++;
  }


  addEvent(document, 'mousemove', this.mouseMoveHandlerHideOptions, false);
//  document.onmousemove=function(e){ optionActor.checkHideOptions(e); }
  this.moveOptions();
}
actor.prototype.hideOptions=function(e){
  removeEvent(document,'mousemove',this.mouseMoveHandlerHideOptions,false);
//  document.onmousemove=null;
  optionActor=null;

  this.showingOptions=false;

  this.tag.style.zIndex=0;
  document.body.removeChild(this.menuDelete);
  document.body.removeChild(this.menuDir);
  document.body.removeChild(this.menuResize);
  document.body.removeChild(this.menuActions.tag);
//  for (var i=0; i<this.menuActions.length; ++i)
//    document.body.removeChild(this.menuActions[i]);

  this.anim.sortActors();
//  alert("hidingOptions: "+this.x+","+this.y);
}

actor.prototype.changeSize=function(){

}

actor.prototype.changeAction=function(action){
  this.frame=0;
  this.action=action;
  this.changes.frame=0;
  this.changes.action=action;
  this.draw();
  if (this.showingOptions){
    for (var i=0; i<this.menuActions.length; ++i){
      if (this.menuActions[i].action!=action){
        this.menuActions[i].style.backgroundColor="#fff";
        this.menuActions[i].onmouseout=setBGColor;
      }else{
        this.menuActions[i].style.backgroundColor="#fdd";
        this.menuActions[i].onmouseout=setSBGColor;
      }
    }
  }
  if (!this.anim.testing && !this.anim.playing){
    images.loadActorAction(this.type,this.action); 
    if (typeof actordefs[this.type].actions[this.action].aend != 'undefined'){
      var aend=actordefs[this.type].actions[this.action].aend;
      if (aend.substr(0,6)=="action")
        images.loadActorAction(this.type,aend.substr(7,aend.length-7));
    }
  }
}

actor.prototype.changeDirection=function(){
  this.direction=-this.direction;
  this.changes.direction=this.direction;
  this.draw();
}


actor.prototype.moveTo=function(px,py){
  this.x=(px-this.anim.vRefpos.x+this.tag.offsetWidth/2)/this.anim.vScale.x;
  this.y=(py-this.anim.vRefpos.y+this.tag.offsetHeight/2)/this.anim.vScale.y;
}

actor.prototype.getImageSrc=function(){
  var imgname;
  if (typeof actordefs[this.type] == 'undefined') { return(""); }
  var actordef=actordefs[this.type].actions[this.action];
  if (actordef.frames!=0){
    if (typeof actordef.framedefs != 'undefined' && typeof actordef.framedefs[this.frame].img != 'undefined'){
      imgname=actordef.framedefs[this.frame].img+"-"+this.direction;
//      alert("imgname: "+imgname);
    }else
      imgname=this.type+"-"+this.action+"-"+this.frame+"-"+this.direction;
  }else
    imgname=this.type+"-"+this.action+"-"+this.direction;
  return(imgname);  
}

actor.prototype.testDraw=function(){
  this.anim.imgsList[this.getImageSrc()]=null;
}

actor.prototype.draw=function(){
  var imgname=this.getImageSrc();
  if (this.anim.testing){
    this.anim.imgsList[imgname]=null;
    return;
  }
  if (!(imgname in images.imgsList)){ /* alert("Missing: "+imgname); */ return; }
  this.tag.src=images.imgsList[imgname].src;
  this.tag.owidth=images.imgsList[imgname].width;
  this.tag.oheight=images.imgsList[imgname].height;
//  alert(this.tag.src);
  if (IEPNGcorr){
    this.tag.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.tag.src + "', sizingMethod='scale')";
  }

  this.tag.style.width = Math.floor(this.scale*this.anim.vScale.x/800.0*this.tag.owidth)+"px";
  this.tag.style.height = Math.floor(this.scale*this.anim.vScale.x/800.0*this.tag.oheight)+"px";
  this.tag.style.left = (this.anim.vRefpos.x + this.x*this.anim.vScale.x - this.tag.offsetWidth/2)+"px";
  this.tag.style.top = (this.anim.vRefpos.y + this.y*this.anim.vScale.y - this.tag.offsetHeight/2)+"px";
//  this.tag.style.left = Math.floor(_actor.x*UIbackground.offsetWidth-_actor.img.offsetWidth/2+p[0])+"px";
//  this.tag.style.top = Math.floor(_actor.y*UIbackground.offsetHeight-_actor.img.offsetHeight/2+p[1])+"px";
}

actor.prototype.replace=function(tag){
  var tmpv={};
  findPos(tag,tmpv);

  this.draw();
  this.scale = tag.offsetWidth*800.0/(this.anim.vScale.x*this.tag.owidth);
  this.tag.style.width = Math.floor(this.scale*this.tag.owidth*this.anim.vScale.x/800.0)+"px";
  this.tag.style.height = Math.floor(this.scale*this.tag.oheight*this.anim.vScale.x/800.0)+"px";

  this.x = (tmpv.x-this.anim.vRefpos.x+this.tag.offsetWidth/2)/this.anim.vScale.x;
  this.y = (tmpv.y-this.anim.vRefpos.y+this.tag.offsetHeight/2)/this.anim.vScale.y;

  this.draw();

  tag.style.visibility="hidden";
}

actor.prototype.remove=function(){
  objCallbackRemove(this);
/*
  objCallbackRemove(this.mouseMoveHandler);
  objCallbackRemove(this.mouseUpHandler);
  objCallbackRemove(this.resizeMouseMoveHandler);
  objCallbackRemove(this.resizeMouseUpHandler);
*/
  if (this.showingOptions)
    this.hideOptions();
  document.body.removeChild(this.tag);
}


function snow(anim){
  this.anim=anim;
  this.changes={};
  this.tag=createActorTag();
  this.tag.src="snow.png";
  this.count=Math.floor(Math.random()*10);
  this.dx = 0.0;
//  this.ax = Math.random()-0.5;
  this.ax = 200.0*(Math.random()-0.5);
  if (this.ax > 0.0) this.ax += 100.0;
  else this.ax-=100.0;
  this.y=0.0;
  this.x=Math.random();
  this.scale=1.0;
}

snow.prototype.update=function(forward){
  var timeStep=1;
//  if (!forward)
//    timeStep=-1
  this.y += 10.0*timeStep*this.scale/1000.0;
  this.x += this.dx*timeStep*this.scale/1000.0
  this.dx += this.ax*timeStep*this.scale/1000.0;
//  alert(this.x+","+this.y+" : "+this.dx+" : "+this.ax);
  this.count--;

  if (this.count<0){
    this.count=Math.floor(Math.random()*10);
    this.ax = 200.0*(Math.random()-0.5);
    if (this.ax > 0.0) this.ax += 100.0;
    else this.ax-=100.0;
  }

  if (this.y > 1.0){
    this.y=0.0;
    this.x=Math.random();
  }
}

snow.prototype.draw=function(){
/*
//  this.tag.src=images.imgsList[this.getImageSrc()].src;
  if (IEPNGcorr){
    this.tag.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.tag.src + "', sizingMethod='scale')";
  }
*/
  this.tag.style.width = Math.floor(this.scale*this.anim.vScale.x*this.tag.owidth)+"px";
  this.tag.style.height = Math.floor(this.scale*this.anim.vScale.x*this.tag.oheight)+"px";
  this.tag.style.left = (this.anim.vRefpos.x + this.x*this.anim.vScale.x - this.tag.offsetWidth/2)+"px";
  this.tag.style.top = (this.anim.vRefpos.y + this.y*this.anim.vScale.y - this.tag.offsetHeight/2)+"px";
}

snow.prototype.remove=function(){
  document.body.removeChild(this.tag);
}




function getActorImg(_actor){
  var imgname;
  var actordef=actordefs[_actor.type].actions[_actor.action];
  if (actordef.frames!=0){
    if (typeof actordef.framedefs != 'undefined' && typeof actordef.framedefs[_actor.frame].img != 'undefined')
      imgname=actordef.framedefs[_actor.frame].img+"-"+_actor.direction;
    else
      imgname=_actor.type+"-"+_actor.action+"-"+_actor.frame+"-"+_actor.direction;
  }else
    imgname=_actor.type+"-"+_actor.action+"-"+_actor.direction;
  return(imgname);  
}

function deleteActor(i){
  if (i<0 || i>=actors.length) { lerror("trying to delete actor out of bounds"); return; }

  document.body.removeChild(actors[i].img);
  actors.splice(i,1);
}

var voiceRecording=true;

function createBallonTag2(type){
  var div=document.createElement("div");
  document.body.appendChild(div);
  div.className='balloon';

  var typeHTML;
  switch (type){
    case "": typeHTML='<img src="/imgs/balloon/balloon_br.png" class="bottom-right">'; break;
    case "arrow": typeHTML='<img src="/imgs/balloon/balloon_arrow.png" class="bottom-arrow"><img src="/imgs/balloon/balloon_br.png" class="bottom-right2">'; break;
    case "think": typeHTML='<img src="/imgs/balloon/balloon_think.png" class="bottom-think"><img src="/imgs/balloon/balloon_br.png" class="bottom-right2">'; break;
  }

  div.innerHTML='<img src="/imgs/balloon/balloon_tl.png" class="top-left"><div class="top"></div><img src="/imgs/balloon/balloon_tr.png" class="top-right"></div><div class="insideleft"><div class="insideright"><div class="inside"><p class="gapsaver"></p><p class="b_ind">0</p><p class="b_text">text</p><p class="gapsaver"></p></div></div></div><img src="/imgs/balloon/balloon_bl.png" class="bottom-left"><div class="bottom"></div>'+typeHTML;
  div.style.position="absolute";
  div.style.left="200px";
  div.style.top="200px";

  var allp=div.getElementsByTagName("p");
  for (var i=0; i<allp.length; ++i){
    if (allp[i].innerHTML=="text")
      { div.btext=allp[i]; }
    if (allp[i].innerHTML=="0")
      { div.count=allp[i]; }
  }
  var alldiv=div.getElementsByTagName("div");
  div.t=alldiv[0];
  div.b=alldiv[4];

  var allimg=div.getElementsByTagName("img");
  div.tl=allimg[0];
  div.tr=allimg[1];
  div.bl=allimg[2];
  if (type!="")
    div.btype=allimg[3];
  div.br=allimg[allimg.length-1];

  div.btext.innerHTML="Click here to add text";

  return(div);
}


function createBalloonTag(type,fontSize,text){
  var div=document.createElement("div");
  document.body.appendChild(div);
  div.className='balloon';

  if (typeof text == 'undefined')
    text=L("Click here to add text");

  var typeHTML;
  switch (type){
    case "": typeHTML='<div class="bottom-right"></div>'; break;
    case "arrow": typeHTML='<div class="bottom-arrow"></div><div class="bottom-right2"></div>'; break;
    case "think": typeHTML='<div class="bottom-think"></div><div class="bottom-right2"></div>'; break;
  }

  div.innerHTML='<div class="top-left"></div><div class="top"></div><div class="top-right"></div><div class="insideleft"><div class="insideright"><div class="inside"><p class="gapsaver"></p><p class="b_ind">0</p><p class="b_text">'+text+'</p><p class="gapsaver"></p></div></div></div><div class="bottom-left"></div><div class="bottom"></div>'+typeHTML;
  div.style.position="absolute";
  div.style.left="200px";
  div.style.top="200px";

  var allp=div.getElementsByTagName("p");
  for (var i=0; i<allp.length; ++i){
    if (allp[i].className=="b_text")
      { div.btext=allp[i]; }
    else if (allp[i].innerHTML=="0")
      { div.count=allp[i]; }
  }
  var alldiv=div.getElementsByTagName("div");
  for (var i=0; i<alldiv.length; ++i){
    if (alldiv[i].className=="bottom-arrow" || alldiv[i].className=="bottom-think")
      { div.img=alldiv[i]; break; }
  }

  div.btext.style.fontSize=fontSize;
//  div.btext.innerHTML=text;

  return(div);
}

function balloon(anim,type){
   if (typeof type == 'undefined')
    type="";
  this.anim=anim;
  this.tag=createBalloonTag(type,Math.floor(20.0*this.anim.vScale.x/800.0)+"px");
  
  this.tag.style.width="190px";
  this.tag.balloon=this;
  this.x=0.5;
  this.y=0.5;
  this.type=type;
  this.direction=1;

  this.showingOptions=false;
  this.warned=false;

  this.changes={};

  this.tag.ondragstart=function(){ return(false); }
  this.tag.onselectstart=function(){ return(false); }
  this.tag.onmouseup=function(){ return(false); }

  this.mouseMoveHandlerHideOptions=objCallback(this,"checkHideOptions");
  this.mouseMoveHandler=objCallback(this,"doMouseMove");
  this.mouseDownHandler=objCallback(this,"doMouseDown");
  this.mouseUpHandler=objCallback(this,"doMouseUp");
  
  this.tag.owidth=this.tag.offsetWidth*800.0/this.anim.vScale.x;
  this.tag.oheight=this.tag.offsetHeight*800.0/this.anim.vScale.x;
//  this.tag.text.style.fontSize=Math.floor(20.0*this.anim.vScale.x/800.0)+"px"; // this is set in createTag

  this.draw();
}

balloon.prototype.remove=function(){
  if (this.showingOptions)
    this.hideOptions();
  document.body.removeChild(this.tag);
}

balloon.prototype.setEditable=function(){
  this.tag.onmousedown=function(e){ return(this.balloon.doMouseDown(e)); }
  this.tag.onmouseover=function(e){ return(this.balloon.showOptions(e)); }
}

var dragBalloon=null;

balloon.prototype.doMouseDown=function(e){
  e = e || window.event;
  dragBalloon=this;
  this.startDragX=e.clientX;
  this.startDragY=e.clientY;
  this.startX=this.x;
  this.startY=this.y;
  this.click=true;

  addEvent(document, 'mousemove', this.mouseMoveHandler, false);
  addEvent(document, 'mouseup', this.mouseUpHandler, false);
//  documentOnMouseMove=document.onmousemove;
//  document.onmousemove=function(e){ dragBalloon.doMouseMove(e); }
//  document.onmouseup=function(e){ dragBalloon.doMouseUp(e); }
  return(false);
}

balloon.prototype.doMouseMove=function(e){
  e = e || window.event;
  this.click=false;
  this.x = this.startX + (e.clientX-this.startDragX)/this.anim.vScale.x;
  this.y = this.startY + (e.clientY-this.startDragY)/this.anim.vScale.y;
  this.tag.style.left = (this.anim.vRefpos.x + this.x*this.anim.vScale.x - this.tag.offsetWidth/2)+"px";
  this.tag.style.top = (this.anim.vRefpos.y + this.y*this.anim.vScale.y - this.tag.offsetHeight/2)+"px";
  this.moveOptions();
  return(false);
}

balloon.prototype.doMouseUp=function(e){
  removeEvent(document, 'mousemove', this.mouseMoveHandler, false);
  removeEvent(document, 'mouseup', this.mouseUpHandler, false);

  if (this.click) { this.showEditor(); return; }

  this.changes.x=this.x;
  this.changes.y=this.y;
  return(false);
}

var editBalloon=null;

balloon.prototype.setText=function(text){
  this.tag.btext.innerHTML=text;
  this.tag.count.innerHTML='';
  this.tag.owidth=this.tag.offsetWidth*800.0/this.anim.vScale.x;
  this.tag.oheight=this.tag.offsetHeight*800.0/this.anim.vScale.x;
  this.draw();
}

balloon.prototype.pointTo=function(tag){
  this.x=(tag.offsetLeft + tag.offsetWidth/2 - this.direction*40 - this.anim.vRefpos.x)/this.anim.vScale.x;
  this.y=(tag.offsetTop - this.tag.offsetHeight/2 - 40 - this.anim.vRefpos.y)/this.anim.vScale.y;
//  this.tag.style.left = (tag.offsetLeft + tag.offsetWidth/2 - this.tag.offsetWidth/2 - this.direction*40)+"px";
//  this.tag.style.top = (tag.offsetTop - this.tag.offsetHeight - 40)+"px";
  this.draw();
//  this.tag.style.left = (this.anim.vRefpos.x + this.x*this.anim.vScale.x - this.tag.offsetWidth/2)+"px";
//  this.tag.style.top = (this.anim.vRefpos.y + this.y*this.anim.vScale.y - this.tag.offsetHeight/2)+"px";
}

balloon.prototype.updateText=function(editor){
  var txt=editor.value;
  txt=txt.replace(/\n/g,"<br>");
  this.tag.btext.innerHTML=txt;
  this.changes.tag={btext:{innerHTML:txt}};
  this.tag.count.innerHTML=8+Math.floor(editor.value.length/2.0);
  this.tag.owidth=this.tag.offsetWidth*800.0/this.anim.vScale.x;
  this.tag.oheight=this.tag.offsetHeight*800.0/this.anim.vScale.x;
  this.draw();
}

balloon.prototype.doneEditing=function(){
  document.body.removeChild(this.menuEditor);
  editBalloon=null;
}

balloon.prototype.showEditor=function(){
  if (editBalloon != null)
    editBalloon.doneEditing();
  editBalloon=this;

  this.menuEditor=document.createElement("div");
  document.body.appendChild(this.menuEditor);

  this.menuEditor.style.zIndex="1001";
  this.menuEditor.style.position="absolute";
  this.menuEditor.style.backgroundColor='#fff';
  this.menuEditor.style.border="1px solid #333";
  this.menuEditor.style.padding="15px 15px 15px 15px";

  var txt=this.tag.btext.innerHTML;
  txt=txt.replace(/<br>/g,"\n");
  this.menuEditor.innerHTML='<textarea onkeypress="editBalloon.updateText(this)" onchange="editBalloon.updateText(this)">'+txt+'</textarea><br><a href="#" onclick="editBalloon.doneEditing(); return(false);">'+L('save')+'</a>';

  this.menuEditor.style.top=this.tag.offsetTop+this.tag.offsetHeight/2-this.menuEditor.offsetHeight/2+"px";
  this.menuEditor.style.left=this.tag.offsetLeft+this.tag.offsetWidth/2-this.menuEditor.offsetWidth/2+"px";
}


//var optionBalloon=null;

balloon.prototype.checkHideOptions=function(e){
  e = e || window.event;
  if (typeof window.pageYOffset == 'undefined') window.pageYOffset = document.body.scrollTop;
  if (typeof window.pageXOffset == 'undefined') window.pageXOffset = document.body.scrollLeft;

  if (window.pageXOffset+e.clientX < this.tag.offsetLeft-5 || window.pageXOffset+e.clientX > this.menuDelete.offsetLeft+this.menuDelete.offsetWidth+5 ||
      window.pageYOffset+e.clientY < this.menuDelete.offsetTop-5 || (this.type!="" && window.pageYOffset+e.clientY > this.menuDir.offsetTop+this.menuDir.offsetHeight+5 || this.type=="" && window.pageYOffset+e.clientY > this.tag.offsetTop+this.tag.offsetHeight))
    this.hideOptions();
}

balloon.prototype.moveOptions=function(){
  if (!this.showingOptions) return;

  this.menuDelete.style.left = (this.tag.offsetLeft+this.tag.offsetWidth-12)+"px";
  this.menuDelete.style.top = (this.tag.offsetTop-24)+"px";

  this.menuEdit.style.left = (this.tag.offsetLeft+this.tag.offsetWidth-12-28)+"px";
  this.menuEdit.style.top = (this.tag.offsetTop-24)+"px";
  if (typeof this.menuVoice != 'undefined'){
    this.menuVoice.style.left = (this.tag.offsetLeft+this.tag.offsetWidth-12-52)+"px";
    this.menuVoice.style.top = (this.tag.offsetTop-24)+"px";
  }

  if (this.type!=""){
    this.menuDir.style.left = (this.tag.offsetLeft+this.tag.offsetWidth/2-12)+"px";
    this.menuDir.style.top = (this.tag.offsetTop+this.tag.offsetHeight)+"px";
  }
}

balloon.prototype.changeDirection=function(){
  this.direction=this.direction*-1;
  this.changes.direction=this.direction;
  this.draw();
}



balloon.prototype.showOptions=function(e){
  if (this.showingOptions) return;

//  if (optionBalloon!=null) optionBalloon.hideOptions();
//  optionBalloon=this;

/*
  var testMenu = document.createElement("div");
  this.tag.appendChild(testMenu);
  testMenu.style.position="absolute";
  testMenu.style.backgroundColor="#00f";
  testMenu.style.border="1px solid #333";
  testMenu.style.left="0px";
  testMenu.style.top="0px";
  testMenu.style.width="20px";
  testMenu.style.height="20px";
*/
 
  this.showingOptions=true;
  this.tag.style.zIndex=100;
  this.menuDelete = createActorTag();
  this.menuDelete.balloon=this;
  this.menuDelete.src="/imgs/actor-delete.png";
  this.menuDelete.style.zIndex=101;
  this.menuDelete.onmousedown=function(){ if (!this.balloon.warned && parseInt(this.balloon.tag.count.innerHTML)>0) { this.balloon.warned=true; alert(L('Please record more frames before deleting the balloon')); } else this.balloon.anim.deleteBalloon(this.balloon.index); }
  this.menuEdit = createActorTag();
  this.menuEdit.balloon=this;
  this.menuEdit.src="/imgs/icon-balloon-edit.png";
  this.menuEdit.style.zIndex=101;
  this.menuEdit.onmousedown=function(e){ this.balloon.showEditor(e); }
  if (voiceRecording){
    this.menuVoice = createActorTag();
    this.menuVoice.balloon=this;
    this.menuVoice.src="/imgs/icon-balloon-voice.png";
    this.menuVoice.style.zIndex=101;
    this.menuVoice.onmousedown=function(e){ this.balloon.anim.sound.showVoiceEditor(this.balloon.tag); }
  }
  if (this.type!=""){
    this.menuDir = createActorTag();
    this.menuDir.balloon=this;
    this.menuDir.src="/imgs/actor-direction.png";
    this.menuDir.style.zIndex=101;
    this.menuDir.onmousedown=function(){ this.balloon.changeDirection(); }
  }
//  alert(this.tag.offsetHeight);

  addEvent(document, 'mousemove', this.mouseMoveHandlerHideOptions, false);
//  document.onmousemove=function(e){ optionBalloon.checkHideOptions(e); }
  this.moveOptions();
}
balloon.prototype.hideOptions=function(e){
  removeEvent(document, 'mousemove', this.mouseMoveHandlerHideOptions, false);
//  document.onmousemove=null;
//  optionBalloon=null;

  this.showingOptions=false;

  this.tag.style.zIndex=100;
  document.body.removeChild(this.menuDelete);
  document.body.removeChild(this.menuEdit);
  if (typeof this.menuVoice != 'undefined')
    document.body.removeChild(this.menuVoice);
  if (this.type!="")
    document.body.removeChild(this.menuDir);
}

balloon.prototype.updateCustom=function(){
  var txt=this.tag.btext.innerHTML;
  var res=txt.match(/{[^} ]+}/g);
  var modified=true;
//  alert('txt: '+txt);
  if (res==null) return;

  for (var i=0; i<res.length; ++i){
    var cname=res[i].substr(1,res[i].length-2);
    if (typeof this.anim.custom[cname] != 'undefined'){
      var re=new RegExp('{'+cname+'}','g');
      txt=txt.replace(re,this.anim.custom[cname]);
//      alert(txt);
      modified=true;
    }
  }
  if (modified)
    this.tag.btext.innerHTML=txt;
}

balloon.prototype.draw=function(){
  if (this.anim.playing){
    this.tag.count.innerHTML="&nbsp;";
    this.updateCustom();
  }
  if (Math.floor(this.tag.owidth*this.anim.vScale.x/800.0)>53)
    this.tag.style.width = Math.floor(this.tag.owidth*this.anim.vScale.x/800.0)+"px";
  else
    this.tag.style.width = "53px";

  if (Math.floor(this.tag.oheight*this.anim.vScale.x/800.0)>53)
    this.tag.style.height = Math.floor(this.tag.oheight*this.anim.vScale.x/800.0)+"px";
  else
    this.tag.style.height = "53px";
  this.tag.style.left = (this.anim.vRefpos.x + this.x*this.anim.vScale.x - this.tag.offsetWidth/2)+"px";
  this.tag.style.top = (this.anim.vRefpos.y + this.y*this.anim.vScale.y - this.tag.offsetHeight/2)+"px";
  this.tag.btext.style.fontSize=Math.floor(20.0*this.anim.vScale.x/800.0)+"px";

  if (this.type=="") return;

//  this.tag.btype.style.height=(this.tag.btype.height*0.5)+"px";

/*
  if (this.direction==1){
    if (this.tag.btype.src!="/imgs/balloon/balloon_"+this.type+".png")
      this.tag.btype.src="/imgs/balloon/balloon_"+this.type+".png";
  }else{
    if (this.tag.btype.src!="/imgs/balloon/balloon_"+this.type+"-rev.png")
      this.tag.btype.src="/imgs/balloon/balloon_"+this.type+"-rev.png";
  }
*/
  if (this.direction==1){
    if (this.tag.img.style.backgroundImage!="url('/imgs/balloon/"+this.type+".png')")
      this.tag.img.style.backgroundImage="url('/imgs/balloon/"+this.type+".png')";
    this.tag.img.style.marginLeft="40%";
  }else{
    if (this.tag.img.style.backgroundImage!="url('/imgs/balloon/"+this.type+"-rev.png')")
      this.tag.img.style.backgroundImage="url('/imgs/balloon/"+this.type+"-rev.png')";
    this.tag.img.style.marginLeft="36%";
  }
}

balloon.prototype.draw2=function(){
  if (this.anim.playing)
    this.tag.count.innerHTML="&nbsp;";
//  this.tag.style.width = Math.floor(this.tag.owidth*this.anim.vScale.x/800.0)+"px";
//  this.tag.style.height = Math.floor(this.tag.oheight*this.anim.vScale.x/800.0)+"px";
  this.tag.style.left = (this.anim.vRefpos.x + this.x*this.anim.vScale.x - this.tag.offsetWidth/2)+"px";
  this.tag.style.top = (this.anim.vRefpos.y + this.y*this.anim.vScale.y - this.tag.offsetHeight/2)+"px";
  this.tag.style.fontSize=Math.floor(20.0*this.anim.vScale.x/800.0)+"px";

  this.tag.tl.style.height=(this.tag.tl.height*0.5)+"px";
  this.tag.tr.style.height=this.tag.tl.style.height;
  this.tag.tr.style.marginTop="-"+this.tag.tl.style.height;
  this.tag.t.style.marginLeft=this.tag.tl.offsetWidth+"px";
  this.tag.t.style.height=this.tag.tl.style.height;
  this.tag.t.style.marginRight=this.tag.tr.offsetWidth+"px";

  this.tag.bl.style.height=(this.tag.bl.height*0.5)+"px";
  this.tag.br.style.height=this.tag.bl.style.height;
  this.tag.br.style.marginTop="-"+this.tag.bl.style.height;
  this.tag.b.style.marginLeft=this.tag.bl.offsetWidth+"px";
  this.tag.b.style.height=this.tag.bl.style.height;
  this.tag.b.style.marginRight=this.tag.br.offsetWidth+"px";

//  div.innerHTML='<img src="/imgs/balloon/balloon_tl.png" class="top-left"><div class="top"></div><img src="/imgs/balloon/balloon_tr.png" class="top-right"></div><div class="insideleft"><div class="insideright"><div class="inside"><p class="gapsaver"></p><p class="b_ind">0</p><p class="b_text">text</p><p class="gapsaver"></p></div></div></div><img src="/imgs/balloon/balloon_bl.png" class="bottom-left"><div class="bottom"></div>'+typeHTML;



  if (this.type=="") return;

  this.tag.btype.style.height=(this.tag.btype.height*0.5)+"px";

  if (this.direction==1){
    if (this.tag.btype.src!="/imgs/balloon/balloon_"+this.type+".png")
      this.tag.btype.src="/imgs/balloon/balloon_"+this.type+".png";
  }else{
    if (this.tag.btype.src!="/imgs/balloon/balloon_"+this.type+"-rev.png")
      this.tag.btype.src="/imgs/balloon/balloon_"+this.type+"-rev.png";
  }

/*
  if (this.direction==1){
    if (this.tag.img.style.backgroundImage!="url('/imgs/balloon/balloon_"+this.type+".png')")
      this.tag.img.style.backgroundImage="url('/imgs/balloon/balloon_"+this.type+".png')";
  }else{
    if (this.tag.img.style.backgroundImage!="url('/imgs/balloon/balloon_"+this.type+"-rev.png')")
      this.tag.img.style.backgroundImage="url('/imgs/balloon/balloon_"+this.type+"-rev.png')";
  }
*/
}






var balloons=new Array();
//var balloon=null;

function changeBalloonType(i,balloontype)
{
  deleteBalloon(i);
  createBalloon(balloontype,i);
}

function deleteBalloon(i){
  if (i<0 || i>=balloons.length) { lerror("trying to delete balloon out of bounds"); return; }
  document.body.removeChild(balloons[i]);
  balloons.splice(i,1);
}

var balloonTypes={balloon: 0, balloonArrow: 1, balloonThink: 2 };

function createBalloon(balloontype,pos){
  var test;
  test=document.createElement("div");
  document.body.appendChild(test);
  test.innerHTML=document.getElementById(balloontype).innerHTML;
  test.style.position="absolute";
  test.style.left="-200px";
  test.style.top="-200px";
  test.onmousedown=doBalloonMouseDown;
  test.onmouseup=doBalloonMouseUp;
  test.onclick=doBalloonClick;
  test.onselectstart=function(){ return(false); }
  test.ondragstart=function(){ return(false); }
  test.type=balloonTypes[balloontype];
/*
  var allimgs = test.getElementsByTagName("img")
  for (var img in allimgs){
    if (allimgs[img].src.substr(allimgs[img].src.length-10)=="delete.png"){ 
      allimgs[img].onclick=function(){ UIdeleteBalloon(test); }
      break;
    }
  }
*/
  resizeBalloon(test,300,200);
  if (typeof pos != 'undefined')
    balloons.splice(pos,0,test);
  else
    balloons[balloons.length]=test;
  return(test);
}

function getBalloonText(_balloon){
  return(_balloon.getElementsByTagName("p")[1].innerHTML);
}

function setBalloonText(_balloon,_text){
  _balloon.getElementsByTagName("p")[1].innerHTML=_text;
}

function editBalloon(_balloon){
  balloon=_balloon;
  var txt=getBalloonText(_balloon);
  txt=txt.replace(/<br>/g,"\n");
  balloonedit.value=txt;
  ballooneditor.style.left=(parseInt(balloon.style.left)+31)+"px";
  ballooneditor.style.top=(parseInt(balloon.style.top)+31)+"px";
  ballooneditor.style.width=(parseInt(balloon.style.width)-62)+"px";
  ballooneditor.style.height=(parseInt(balloon.style.height)-62)+"px";
  balloonedit.style.width=(parseInt(balloon.style.width)-62)+"px";
  balloonedit.style.height=(parseInt(balloon.style.height)-62)+"px";
  ballooneditor.style.display="block";
  ballooneditor.focus();
  balloonedit.focus();
  editingBalloon=true;
  document.getElementById("background").onmouseup=doBalloonMouseUp;
}

var balloonCorner=false;

function doBalloonMouseDown(e){
  if (IE) e=event;
  
  if (editingBalloon){
//    saveEditBalloon();
    return(false);
  }

  balloon=this;
  startDragX = e.clientX; startDragY = e.clientY;
//  alert("offset: "+e.clientX+","+e.clientY+"   style: "+this.style.left+","+this.style.top+","+this.offsetWidth+","+this.offsetHeight);
  if (Math.abs(e.clientX-parseInt(this.style.left)-this.offsetWidth)<30 && Math.abs(e.clientY-parseInt(this.style.top)-this.offsetHeight)<30){
    balloonCorner=true;
    startDragActorX = this.offsetWidth;
    startDragActorY = this.offsetHeight;
  }else{
    balloonCorner=false;
    startDragActorX = parseInt(this.style.left);
    startDragActorY = parseInt(this.style.top);
  }
  this.onmousemove=doBalloonMouseMove;
  document.onmousemove=doBalloonMouseMove;
  document.onmouseup=doBalloonMouseUp;
  return(false);
}

function doBalloonMouseMove(e){
  if (IE) e=event;
  startDrag=true;
  if (balloonCorner){
//    dragBalloon.style.width = startDragActorX + e.clientX - startDragX;
//    dragBalloon.style.height = startDragActorY + e.clientY - startDragY;
    resizeBalloon(balloon,startDragActorX + e.clientX - startDragX,startDragActorY + e.clientY - startDragY);
  }else{
    balloon.style.left = (startDragActorX + e.clientX - startDragX)+"px";
    balloon.style.top = (startDragActorY + e.clientY - startDragY)+"px";
  }
}

var editingBalloon=false;

function doBalloonMouseUp(e){
  if (balloon==null) return;
  
  if (IE) e=event;
  if (FF){ e.offsetX=e.layerX; e.offsetY=e.layerY; }
  
  balloon.onmousemove=null;
  document.onmousemove=null;
  document.onmouseup=null;
  if (startDrag){
    if (balloonCorner){
//      dragBalloon.style.width = startDragActorX + e.clientX - startDragX;
//      dragBalloon.style.height = startDragActorY + e.clientY - startDragY;
      resizeBalloon(balloon,startDragActorX + e.clientX - startDragX,startDragActorY + e.clientY - startDragY);
    }else{
      balloon.style.left = (startDragActorX + e.clientX - startDragX)+"px";
      balloon.style.top = (startDragActorY + e.clientY - startDragY)+"px";
    }
    startDrag=false;
  }else{
    if (Math.abs(e.clientX-parseInt(this.style.left)-this.offsetWidth)<30 && Math.abs(e.clientY-parseInt(this.style.top))<30){
      ballooneditor.style.display="none";
      editingBalloon=false;
      deleteBalloon(balloons.indexOf(balloon));
      balloon=null;
    }else if (editingBalloon)
      saveEditBalloon();
    else{
      balloon=this;
      editBalloon(balloon);
    }
  }
}

function doBalloonClick(e){
  e = e || window.event;
  if (FF){ e.offsetX=e.layerX; e.offsetY=e.layerY; }

  if (balloon != null)
    balloon.onmousemove=null;
  document.onmousemove=null;
  document.onmouseup=null;

  balloon=this;
}

function saveEditBalloon(){
  editingBalloon=false;
  var txt=balloonedit.value;
  txt=txt.replace(/\n/g,"<br>");
  balloon.getElementsByTagName("p")[1].innerHTML=txt;
  ballooneditor.style.display="none";
  document.getElementById("background").onmouseup=null;
}

/*
function doBalloonMenuKeyPress(e){
  var code;
  
  if (e.keyCode) code = e.keyCode;
  else if (e.which) code = e.which;
  
  if (code==13){
    balloon.getElementsByTagName("p")[0].innerHTML=balloonedit.value;
    balloonmenu.style.display="none";
  }
}
*/




function createSceneTag(){
  var img;

  img = document.createElement("img");
  document.body.appendChild(img);

  img.style.position="absolute";
  return(img);
}



function scene(anim,imgtag){
  this.img=imgtag;
  this.anim=anim;
  if (typeof imgtag == 'undefined')
    this.img = createSceneTag();

  this.menu=null;
  this.current="";

  this.images=new cimages;

  if (imgtag.tagName == "IMG"){
    this.img.scene=this;
//    this.img.onmousedown=function(e){ return(this.scene.showMenu(e)); }
    this.img.ondragstart=function(){ return(false); }
    this.img.onselectstart=function(){ return(false); }
    this.loadAll();
  }

  this.mouseMoveHandler=objCallback(this,"checkHideMenu");
}

scene.prototype.doneLoading=function(){
  this.select(this.current);
  this.anim.doResize();
}

scene.prototype.loadAll=function(){
  var last;
  for (var i in scenedefs){
    if (i == "indexOf") continue;
    this.current=i;
//    this.images.load(i,"/scenes/"+scenedefs[i].file);
    this.images.load("icon-"+i,"/scenes/icon-"+scenedefs[i].file);
  }
  this.images.onLoadedAdd(objCallback(this,"doneLoading"));
//  this.select(this.current);
  this.images.load(this.current,"/scenes/"+scenedefs[this.current].file);
}

scene.prototype.select=function(name){
  if (name=="") return;

/*
  if (!(name in this.images.imgsList)){
    alert("loading: "+name);
    this.current=name;
    this.images.load(name,"/scenes/"+scenedefs[name].file);
    return;
  }
*/
  this.img.src="/scenes/"+scenedefs[name].file;
//  this.img.src=this.images.imgsList[name].src;
  this.current=name;
}

var curScene;


scene.prototype.checkHideMenu=function(e){
  e=e||window.event;
  if (typeof window.pageYOffset == 'undefined') window.pageYOffset = document.body.scrollTop;
  if (typeof window.pageXOffset == 'undefined') window.pageXOffset = document.body.scrollLeft;

  if (window.pageXOffset+e.clientX < this.menu.offsetLeft-5 || window.pageXOffset+e.clientX > this.menu.offsetLeft+this.menu.offsetWidth+5 ||
      window.pageYOffset+e.clientY < this.menu.offsetTop-5 || window.pageYOffset+e.clientY > this.menu.offsetTop+this.menu.offsetHeight+5)
    this.hideMenu();
}

scene.prototype.hideMenu=function(){
  if (this.menu==null) return;

  document.body.removeChild(this.menu);
  this.menu=null;
  removeEvent(document, 'mousemove', this.mouseMoveHandler, false);
}

scene.prototype.showMenu=function(e){
  e = e || window.event;

  if (typeof window.pageYOffset == 'undefined') window.pageYOffset = document.body.scrollTop;
  if (typeof window.pageXOffset == 'undefined') window.pageXOffset = document.body.scrollLeft;

  if (this.menu != null){
//    this.menu.style.top=window.pageYOffset+e.clientY+"px";
//    this.menu.style.left=window.pageXOffset+e.clientX+"px";
    this.hideMenu();
    return;
  }

  curScene=this;

  this.menu=document.createElement("div"); //getElementById("scenes");
  document.body.appendChild(this.menu);
  this.menu.style.position='absolute';
  this.menu.style.textAlign='left';
  this.menu.style.padding="5px 5px 5px 5px";
  this.menu.style.zIndex="1010";
  this.menu.style.width="321px";
  this.menu.style.border="1px solid #333";
  this.menu.style.backgroundColor='#fff';

  var a;
  var tmp="";  

  tmp += '<div style="text-align: right"><a href="#" onclick="parentNode.scene.hideMenu();return(false);">'+L('close')+'</a></div>';

  for (a in scenedefs){
    if (a == "indexOf") continue;
    if (!this.anim.showPrivate && typeof scenedefs[a].private != 'undefined') continue;
    tmp+="<div ondragstart=\"return(false);\" onselectstart=\"return(false);\" onclick=\"this.scene.select('"+a+"');\" class=\"sceneitem\" onmouseover=\"this.style.backgroundColor='#aaaaff';\" onmouseout=\"this.style.backgroundColor='#ffffff';\"><img src=\"/scenes/icon-"+scenedefs[a].file+"\" style=\"vertical-align: middle; margin-bottom: 5px\"><br>"+scenedefs[a].label+"</div>";
//    tmp+="<div onclick=\"parentNode.anim.addActor('"+a+"').setEditable(); parentNode.anim.hideActors(); return(false);\" class=\"actoritem\" onmouseover=\"this.style.backgroundColor='#aaaaff';\" onmouseout=\"this.style.backgroundColor='#ffffff';\"><img onselectstart=\"return(false);\" ondragstart=\"return(false);\" src=\""+getActorDir(a)+"/icon-"+a+"-stand.png\"><br>"+label+"</div>";
  }
  this.menu.innerHTML=tmp;

  var res=this.menu.getElementsByTagName("div");
  for (var i in res){
    res[i].scene=this;
  }


  if (typeof e != 'undefined' && typeof e.tagName != 'undefined'){
//    alert(e);
    var pos={};
    findPos(e,pos);
//    alert(pos.x+","+pos.y);
    if (pos.y+e.offsetHeight+this.menu.offsetHeight < sHeight)
      this.menu.style.top=pos.y+e.offsetHeight+"px";
    else
      this.menu.style.top=(pos.y-this.menu.offsetHeight)+"px";
//    this.menu.style.top=pos.y+e.offsetHeight+"px";
    if (pos.x+e.offsetWidth/2+this.menu.offsetWidth/2 < sWidth)
      this.menu.style.left=pos.x+e.offsetWidth/2-this.menu.offsetWidth/2+"px";
    else
      this.menu.style.left=sWidth-this.menu.offsetWidth+"px";
  }else{
    this.menu.style.top=window.pageYOffset+e.clientY+"px";
    this.menu.style.left=window.pageXOffset+e.clientX+"px";
    addEvent(document, 'mousemove', this.mouseMoveHandler, false);
  }

  return(false);
}



function soundCreateManager(){
  if (typeof document["sm"] != 'undefined') return;

  smdiv=document.createElement("div");
  document.body.appendChild(smdiv);
  smdiv.style.position="absolute";
  smdiv.style.zIndex="2000";
  smdiv.style.left="-400px";
  smdiv.style.top="-300px";
  smdiv.id="smdiv";
  sm=document.createElement("div");
  smdiv.appendChild(sm);
  sm.id="sm";

  swfobject.embedSWF("/flash/soundobj.swf", "sm", "300", "150", "9.0.0");
//  document["sm"].netConnect("www.funtuns.com");
}

var soundIndex=0;

function csound(anim){
  this.isMicInit=false;
  this.voice=0;
  this.recCount=0;
  this.anim=anim;
  this.loadedCount=0;
  this.soundCount=0;
}

csound.prototype.init=function(){
  soundCreateManager();
}

csound.prototype.loadAll=function(){
  for (var s in sounddefs)
    this.load(s);
}

function soundDoneLoading(){
  ++curSound.loadedCount;
  linfo("sound | done loading: "+curSound.loadedCount+"/"+curSound.soundCount);
}

function soundErrorLoading(){
}

csound.prototype.load=function(name){
  if (typeof document["sm"].loadSoundFile == 'undefined') return;
  curSound=this;
  if (name in sounddefs && typeof sounddefs[name].index != 'undefined') return;
  sounddefs[name].index=soundIndex;
  ++soundIndex;
  ++this.soundCount;
  linfo("sound | loading: "+name+" file: "+sounddefs[name].file+" index: "+sounddefs[name].index);
  document["sm"].loadSoundFile(sounddefs[name].file);
}

csound.prototype.play=function(name){
  if (typeof document["sm"].playSound == 'undefined') return;
  if (!(name in sounddefs)) return;
  if (typeof sounddefs[name].index == 'undefined'){
    this.load(name);
  }

  if (this.anim.testing) return; //do not play sounds when testing play
  linfo("sound | playing: "+name+" file: "+sounddefs[name].file+" index: "+sounddefs[name].index );

  document["sm"].playSound(sounddefs[name].index);
}

csound.prototype.hideVoiceEditor=function(){
  document.body.removeChild(this.voiceMenu); 
  this.voiceMenu=null;
}

csound.prototype.showVoiceEditor=function(tag){
  if (this.voiceMenu!=null) 
    this.hideVoiceEditor();

  var voiceMenu = document.createElement("div");
  this.voiceMenu=voiceMenu;
  document.body.appendChild(voiceMenu);
  var voiceMenuStatus = document.createElement("div");
  this.voiceMenu.stat=voiceMenuStatus;
  voiceMenu.appendChild(voiceMenuStatus);
  var voiceMenuLinks = document.createElement("div");
  voiceMenu.appendChild(voiceMenuLinks);
  voiceMenuStatus.innerHTML="...";
  voiceMenu.style.position="absolute";
  voiceMenu.style.backgroundColor="#fff";
  voiceMenu.style.left="100px";
  voiceMenu.style.top="100px";
  voiceMenu.style.width="200px";
  voiceMenu.style.height="60px";
  voiceMenu.style.border="1px solid #333";
  voiceMenu.style.padding="20px 20px 20px 20px"
  voiceMenu.style.textAlign="center";
  voiceMenu.style.zIndex="1002";
  voiceMenu.balloon=tag;
  voiceMenuLinks.sound=this;
  this.voice=this.recCount;

  voiceMenuLinks.innerHTML='<a href="#" onclick="this.parentNode.sound.record(); return(false);">record</a> <a href="#" onclick="this.parentNode.sound.stopSound(); return(false);">stop</a> <a href="#" onclick="this.parentNode.sound.testRec(this.parentNode.sound.voice); return(false);">play</a> <a href="#" onclick="this.parentNode.sound.playRec(this.parentNode.sound.voice); return(false);">save</a> <a href="#" onclick="this.parentNode.sound.hideVoiceEditor(); return(false);">hide</a>';

  if (typeof tag != 'undefined'){
    var pos={};
    findPos(tag,pos);
    voiceMenu.style.top=pos.y+tag.offsetHeight/2-voiceMenu.offsetHeight/2+"px";
    voiceMenu.style.left=pos.x+tag.offsetWidth/2-voiceMenu.offsetWidth/2+"px";
  }
}

csound.prototype.micInit=function(){
  // show flash div
  $("smdiv").style.left=(sWidth/2-$("smdiv").offsetWidth/2)+"px";
  $("smdiv").style.top=(sHeight/2-$("smdiv").offsetHeight/2)+"px";
  //

  document["sm"].micOn();
  this.isMicInit=true;
}

function micRecordStart(){
  curSound.voiceMenu.stat.innerHTML="recording...";
}

csound.prototype.record=function(name){
  if (this.isVoiceRecording) return;

  curSound=this;

  if (!this.isMicInit)
    { this.micInit(); return; }

//  alert("starting to record: "+"funtuns-"+this.anim.mid+"-"+this.recCount);
  document["sm"].startRec("funtuns-"+this.anim.sndid+"-"+this.recCount);
  this.isVoiceRecording=true;
  this.recStart = new Date();
}

csound.prototype.stopSound=function(){
  document["sm"].stopSound();
  if (this.isVoiceRecording){
    var recEnd = new Date();
    this.recSeconds = (recEnd.valueOf() - this.recStart.valueOf())/1000.0;
    this.isVoiceRecording=false;
//    alert("recorded for: "+this.recSeconds+" seconds");
    curSound.voiceMenu.stat.innerHTML="...";
  }
}

csound.prototype.testRec=function(voice){
  if (this.voice==-1) return;
//  alert("testing record: "+"funtuns-"+this.anim.mid+"-"+voice);
  document["sm"].playRec("funtuns-"+this.anim.sndid+"-"+voice);
}

csound.prototype.playRec=function(voice){
  if (!this.anim.playing){ this.voiceMenu.balloon.count.innerHTML=6+Math.floor(this.recSeconds*fps); this.recCount++; this.hideVoiceEditor(); return; }
  if (this.anim.testing) return;
  
  document["sm"].playRec("funtuns-"+this.anim.sndid+"-"+voice);
}

function micInitDone()
{
  document.getElementById("smdiv").style.left="-400px";
  document.getElementById("smdiv").style.top="-300px";
  curSound.record();
}

//var sounds=new csounds;







function stopMusic(){
  if (IE)
    document.getElementById("IEsoundPlayer").src="";
  else
    document.getElementById("soundPlayer").innerHTML="";
}

function playSound(surl){
  if (IE){
    document.getElementById("IEsoundPlayerFX").src = surl;
  }else{
    document.getElementById("soundPlayerFX").innerHTML=
      '<embed src="'+surl+'" hidden="true" autostart="true" loop="false">';
  }
}

function playMusic(_music){
  music=_music;
  if (IE){
    document.getElementById("IEsoundPlayer").src = musicdefs[music];
  }else{
    document.getElementById("soundPlayer").innerHTML=
      '<embed src="'+musicdefs[music]+'" hidden="true" autostart="true" loop="false">';
  }
}
/* SWFObject v2.1 <http://code.google.com/p/swfobject/>
	Copyright (c) 2007-2008 Geoff Stearns, Michael Williams, and Bobby van der Sluis
	This software is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
*/
var swfobject=function(){var b="undefined",Q="object",n="Shockwave Flash",p="ShockwaveFlash.ShockwaveFlash",P="application/x-shockwave-flash",m="SWFObjectExprInst",j=window,K=document,T=navigator,o=[],N=[],i=[],d=[],J,Z=null,M=null,l=null,e=false,A=false;var h=function(){var v=typeof K.getElementById!=b&&typeof K.getElementsByTagName!=b&&typeof K.createElement!=b,AC=[0,0,0],x=null;if(typeof T.plugins!=b&&typeof T.plugins[n]==Q){x=T.plugins[n].description;if(x&&!(typeof T.mimeTypes!=b&&T.mimeTypes[P]&&!T.mimeTypes[P].enabledPlugin)){x=x.replace(/^.*\s+(\S+\s+\S+$)/,"$1");AC[0]=parseInt(x.replace(/^(.*)\..*$/,"$1"),10);AC[1]=parseInt(x.replace(/^.*\.(.*)\s.*$/,"$1"),10);AC[2]=/r/.test(x)?parseInt(x.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof j.ActiveXObject!=b){var y=null,AB=false;try{y=new ActiveXObject(p+".7")}catch(t){try{y=new ActiveXObject(p+".6");AC=[6,0,21];y.AllowScriptAccess="always"}catch(t){if(AC[0]==6){AB=true}}if(!AB){try{y=new ActiveXObject(p)}catch(t){}}}if(!AB&&y){try{x=y.GetVariable("$version");if(x){x=x.split(" ")[1].split(",");AC=[parseInt(x[0],10),parseInt(x[1],10),parseInt(x[2],10)]}}catch(t){}}}}var AD=T.userAgent.toLowerCase(),r=T.platform.toLowerCase(),AA=/webkit/.test(AD)?parseFloat(AD.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,q=false,z=r?/win/.test(r):/win/.test(AD),w=r?/mac/.test(r):/mac/.test(AD);/*@cc_on q=true;@if(@_win32)z=true;@elif(@_mac)w=true;@end@*/return{w3cdom:v,pv:AC,webkit:AA,ie:q,win:z,mac:w}}();var L=function(){if(!h.w3cdom){return }f(H);if(h.ie&&h.win){try{K.write("<script id=__ie_ondomload defer=true src=//:><\/script>");J=C("__ie_ondomload");if(J){I(J,"onreadystatechange",S)}}catch(q){}}if(h.webkit&&typeof K.readyState!=b){Z=setInterval(function(){if(/loaded|complete/.test(K.readyState)){E()}},10)}if(typeof K.addEventListener!=b){K.addEventListener("DOMContentLoaded",E,null)}R(E)}();function S(){if(J.readyState=="complete"){J.parentNode.removeChild(J);E()}}function E(){if(e){return }if(h.ie&&h.win){var v=a("span");try{var u=K.getElementsByTagName("body")[0].appendChild(v);u.parentNode.removeChild(u)}catch(w){return }}e=true;if(Z){clearInterval(Z);Z=null}var q=o.length;for(var r=0;r<q;r++){o[r]()}}function f(q){if(e){q()}else{o[o.length]=q}}function R(r){if(typeof j.addEventListener!=b){j.addEventListener("load",r,false)}else{if(typeof K.addEventListener!=b){K.addEventListener("load",r,false)}else{if(typeof j.attachEvent!=b){I(j,"onload",r)}else{if(typeof j.onload=="function"){var q=j.onload;j.onload=function(){q();r()}}else{j.onload=r}}}}}function H(){var t=N.length;for(var q=0;q<t;q++){var u=N[q].id;if(h.pv[0]>0){var r=C(u);if(r){N[q].width=r.getAttribute("width")?r.getAttribute("width"):"0";N[q].height=r.getAttribute("height")?r.getAttribute("height"):"0";if(c(N[q].swfVersion)){if(h.webkit&&h.webkit<312){Y(r)}W(u,true)}else{if(N[q].expressInstall&&!A&&c("6.0.65")&&(h.win||h.mac)){k(N[q])}else{O(r)}}}}else{W(u,true)}}}function Y(t){var q=t.getElementsByTagName(Q)[0];if(q){var w=a("embed"),y=q.attributes;if(y){var v=y.length;for(var u=0;u<v;u++){if(y[u].nodeName=="DATA"){w.setAttribute("src",y[u].nodeValue)}else{w.setAttribute(y[u].nodeName,y[u].nodeValue)}}}var x=q.childNodes;if(x){var z=x.length;for(var r=0;r<z;r++){if(x[r].nodeType==1&&x[r].nodeName=="PARAM"){w.setAttribute(x[r].getAttribute("name"),x[r].getAttribute("value"))}}}t.parentNode.replaceChild(w,t)}}function k(w){A=true;var u=C(w.id);if(u){if(w.altContentId){var y=C(w.altContentId);if(y){M=y;l=w.altContentId}}else{M=G(u)}if(!(/%$/.test(w.width))&&parseInt(w.width,10)<310){w.width="310"}if(!(/%$/.test(w.height))&&parseInt(w.height,10)<137){w.height="137"}K.title=K.title.slice(0,47)+" - Flash Player Installation";var z=h.ie&&h.win?"ActiveX":"PlugIn",q=K.title,r="MMredirectURL="+j.location+"&MMplayerType="+z+"&MMdoctitle="+q,x=w.id;if(h.ie&&h.win&&u.readyState!=4){var t=a("div");x+="SWFObjectNew";t.setAttribute("id",x);u.parentNode.insertBefore(t,u);u.style.display="none";var v=function(){u.parentNode.removeChild(u)};I(j,"onload",v)}U({data:w.expressInstall,id:m,width:w.width,height:w.height},{flashvars:r},x)}}function O(t){if(h.ie&&h.win&&t.readyState!=4){var r=a("div");t.parentNode.insertBefore(r,t);r.parentNode.replaceChild(G(t),r);t.style.display="none";var q=function(){t.parentNode.removeChild(t)};I(j,"onload",q)}else{t.parentNode.replaceChild(G(t),t)}}function G(v){var u=a("div");if(h.win&&h.ie){u.innerHTML=v.innerHTML}else{var r=v.getElementsByTagName(Q)[0];if(r){var w=r.childNodes;if(w){var q=w.length;for(var t=0;t<q;t++){if(!(w[t].nodeType==1&&w[t].nodeName=="PARAM")&&!(w[t].nodeType==8)){u.appendChild(w[t].cloneNode(true))}}}}}return u}function U(AG,AE,t){var q,v=C(t);if(v){if(typeof AG.id==b){AG.id=t}if(h.ie&&h.win){var AF="";for(var AB in AG){if(AG[AB]!=Object.prototype[AB]){if(AB.toLowerCase()=="data"){AE.movie=AG[AB]}else{if(AB.toLowerCase()=="styleclass"){AF+=' class="'+AG[AB]+'"'}else{if(AB.toLowerCase()!="classid"){AF+=" "+AB+'="'+AG[AB]+'"'}}}}}var AD="";for(var AA in AE){if(AE[AA]!=Object.prototype[AA]){AD+='<param name="'+AA+'" value="'+AE[AA]+'" />'}}v.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+AF+">"+AD+"</object>";i[i.length]=AG.id;q=C(AG.id)}else{if(h.webkit&&h.webkit<312){var AC=a("embed");AC.setAttribute("type",P);for(var z in AG){if(AG[z]!=Object.prototype[z]){if(z.toLowerCase()=="data"){AC.setAttribute("src",AG[z])}else{if(z.toLowerCase()=="styleclass"){AC.setAttribute("class",AG[z])}else{if(z.toLowerCase()!="classid"){AC.setAttribute(z,AG[z])}}}}}for(var y in AE){if(AE[y]!=Object.prototype[y]){if(y.toLowerCase()!="movie"){AC.setAttribute(y,AE[y])}}}v.parentNode.replaceChild(AC,v);q=AC}else{var u=a(Q);u.setAttribute("type",P);for(var x in AG){if(AG[x]!=Object.prototype[x]){if(x.toLowerCase()=="styleclass"){u.setAttribute("class",AG[x])}else{if(x.toLowerCase()!="classid"){u.setAttribute(x,AG[x])}}}}for(var w in AE){if(AE[w]!=Object.prototype[w]&&w.toLowerCase()!="movie"){F(u,w,AE[w])}}v.parentNode.replaceChild(u,v);q=u}}}return q}function F(t,q,r){var u=a("param");u.setAttribute("name",q);u.setAttribute("value",r);t.appendChild(u)}function X(r){var q=C(r);if(q&&(q.nodeName=="OBJECT"||q.nodeName=="EMBED")){if(h.ie&&h.win){if(q.readyState==4){B(r)}else{j.attachEvent("onload",function(){B(r)})}}else{q.parentNode.removeChild(q)}}}function B(t){var r=C(t);if(r){for(var q in r){if(typeof r[q]=="function"){r[q]=null}}r.parentNode.removeChild(r)}}function C(t){var q=null;try{q=K.getElementById(t)}catch(r){}return q}function a(q){return K.createElement(q)}function I(t,q,r){t.attachEvent(q,r);d[d.length]=[t,q,r]}function c(t){var r=h.pv,q=t.split(".");q[0]=parseInt(q[0],10);q[1]=parseInt(q[1],10)||0;q[2]=parseInt(q[2],10)||0;return(r[0]>q[0]||(r[0]==q[0]&&r[1]>q[1])||(r[0]==q[0]&&r[1]==q[1]&&r[2]>=q[2]))?true:false}function V(v,r){if(h.ie&&h.mac){return }var u=K.getElementsByTagName("head")[0],t=a("style");t.setAttribute("type","text/css");t.setAttribute("media","screen");if(!(h.ie&&h.win)&&typeof K.createTextNode!=b){t.appendChild(K.createTextNode(v+" {"+r+"}"))}u.appendChild(t);if(h.ie&&h.win&&typeof K.styleSheets!=b&&K.styleSheets.length>0){var q=K.styleSheets[K.styleSheets.length-1];if(typeof q.addRule==Q){q.addRule(v,r)}}}function W(t,q){var r=q?"visible":"hidden";if(e&&C(t)){C(t).style.visibility=r}else{V("#"+t,"visibility:"+r)}}function g(s){var r=/[\\\"<>\.;]/;var q=r.exec(s)!=null;return q?encodeURIComponent(s):s}var D=function(){if(h.ie&&h.win){window.attachEvent("onunload",function(){var w=d.length;for(var v=0;v<w;v++){d[v][0].detachEvent(d[v][1],d[v][2])}var t=i.length;for(var u=0;u<t;u++){X(i[u])}for(var r in h){h[r]=null}h=null;for(var q in swfobject){swfobject[q]=null}swfobject=null})}}();return{registerObject:function(u,q,t){if(!h.w3cdom||!u||!q){return }var r={};r.id=u;r.swfVersion=q;r.expressInstall=t?t:false;N[N.length]=r;W(u,false)},getObjectById:function(v){var q=null;if(h.w3cdom){var t=C(v);if(t){var u=t.getElementsByTagName(Q)[0];if(!u||(u&&typeof t.SetVariable!=b)){q=t}else{if(typeof u.SetVariable!=b){q=u}}}}return q},embedSWF:function(x,AE,AB,AD,q,w,r,z,AC){if(!h.w3cdom||!x||!AE||!AB||!AD||!q){return }AB+="";AD+="";if(c(q)){W(AE,false);var AA={};if(AC&&typeof AC===Q){for(var v in AC){if(AC[v]!=Object.prototype[v]){AA[v]=AC[v]}}}AA.data=x;AA.width=AB;AA.height=AD;var y={};if(z&&typeof z===Q){for(var u in z){if(z[u]!=Object.prototype[u]){y[u]=z[u]}}}if(r&&typeof r===Q){for(var t in r){if(r[t]!=Object.prototype[t]){if(typeof y.flashvars!=b){y.flashvars+="&"+t+"="+r[t]}else{y.flashvars=t+"="+r[t]}}}}f(function(){U(AA,y,AE);if(AA.id==AE){W(AE,true)}})}else{if(w&&!A&&c("6.0.65")&&(h.win||h.mac)){A=true;W(AE,false);f(function(){var AF={};AF.id=AF.altContentId=AE;AF.width=AB;AF.height=AD;AF.expressInstall=w;k(AF)})}}},getFlashPlayerVersion:function(){return{major:h.pv[0],minor:h.pv[1],release:h.pv[2]}},hasFlashPlayerVersion:c,createSWF:function(t,r,q){if(h.w3cdom){return U(t,r,q)}else{return undefined}},removeSWF:function(q){if(h.w3cdom){X(q)}},createCSS:function(r,q){if(h.w3cdom){V(r,q)}},addDomLoadEvent:f,addLoadEvent:R,getQueryParamValue:function(v){var u=K.location.search||K.location.hash;if(v==null){return g(u)}if(u){var t=u.substring(1).split("&");for(var r=0;r<t.length;r++){if(t[r].substring(0,t[r].indexOf("="))==v){return g(t[r].substring((t[r].indexOf("=")+1)))}}}return""},expressInstallCallback:function(){if(A&&M){var q=C(m);if(q){q.parentNode.replaceChild(M,q);if(l){W(l,true);if(h.ie&&h.win){M.style.display="block"}}M=null;l=null;A=false}}}}}();function $(e){ return(document.getElementById(e)); }
function L(s){ if (typeof langStr!='undefined' && typeof langStr[s] != 'undefined') return(langStr[s]); return(s); }

function findPos(obj,pos) {
  pos.x = pos.y = 0;
  if (obj.offsetParent) {
    do {
      pos.x += obj.offsetLeft;
      pos.y += obj.offsetTop;
    } while (obj = obj.offsetParent);
    return(pos);
  }
  pos.x=obj.offsetLeft;
  pos.y=obj.offsetTop;
  return(pos);
}

function getArgs(){
  var url=document.location.href;
  var i=url.indexOf("?");
  if (i==-1) { return({}); }
  url=url.substr(i+1);

  var res={};
  var args=url.split("&");
  for (i=0; i<args.length; ++i){
    var tmp=args[i].split("=");
    res[tmp[0]]=tmp[1];
  }
  return(res);
}

function getImg(src,type)
{
  if (src.indexOf("-")>=0)
    src=src.substr(0,src.indexOf("-"));
  else
    src=src.substr(0,src.indexOf(".png"));
  if (typeof type == 'undefined')
    return(src+".png");
  return(src+"-"+type+".png");
}

function imgOver(tag){
  tag.src=getImg(tag.src,"over");
}
function imgDown(tag){
  tag.src=getImg(tag.src,"down");
}
function imgOut(tag){
  tag.src=getImg(tag.src);
}

function isRightClick(e){
  e = e || window.event;
  if (typeof e.which != 'undefined' && e.which == 3) //Mozilla,Safari,...
    return(true);
  else if (typeof e.button != 'undefined' && e.button==2) //IE
    return(true);
  return(false);
}



var endMenu=null;

function showEnd(){
  c.reset();
  endMenu=createBalloonTag('','16px');
  endMenu.count.innerHTML='';
  endMenu.btext.style.color='#755c44';
  endMenu.btext.style.textAlign='left';
  endMenu.btext.style.padding='0px 5px 0px 5px';
  var tmpstr='';
  if (movuser.length>0)
    tmpstr='<p>'+L('This movie was created by')+': '+movuser+'</p>';
  endMenu.btext.innerHTML='<h3 style="text-align: center; background-color: #7e7; color: #fff">'+L('The End')+'</h3>'+tmpstr+'<ul style="padding-right: 20px"><li><a href="#" onclick="c.play(); hideEnd(); return(false)">'+L('replay')+'</a> '+L('movie')+'</li><li><a href="#" onclick="c.showSend(); hideEnd(); return(false)">'+L('send')+'</a> '+L('to a friend')+'</li><li><a href="/ecards/">'+L('view')+'</a> '+L('more ecards')+'</li><li><a href="/story.php">'+L('make')+'</a> '+L('your own ecard, it is easy!')+'</li></ul>';
  endMenu.style.left=(sWidth/2-endMenu.offsetWidth/2)+"px";
  endMenu.style.top=(sHeight/2-endMenu.offsetHeight/2)+"px";
}
function hideEnd(){
  document.body.removeChild(endMenu);
  endMenu=null;
}



function exitAlert(e){
  var msg = L("You did not save your cartoon yet. You will lose the cartoon you made if you continue!");
  if (!e) { e = window.event; }
  if (e) { e.returnValue = msg; }
  return(msg);
}

var exitAlertOn=false;

function addExitAlert(){
  if (exitAlertOn) return;
  exitAlertOn=true;
  addEvent(window, 'beforeunload', exitAlert, false);
}

function removeExitAlert(){
  exitAlertOn=false;
  removeEvent(window, 'beforeunload', exitAlert, false);
}





var langMenu=null;
function setLang(lang){
  window.location.href="?lang="+lang+"&setlang="+lang;
}
function hideLang(){
  document.body.removeChild(langMenu);
  langMenu=null;
}
function chooseLang(tag){
  if (langMenu!=null) { hideLang(); return(false); }

  langMenu = document.createElement("div");
  document.body.appendChild(langMenu);

  langMenu.className="langMenu";
  var tmp="";
  tmp+='<div onclick="setLang(\'en\');">english <img src="/imgs/lang/gb.gif"></div>';
  tmp+='<div onclick="setLang(\'pl\');">polski <img src="/imgs/lang/pl.gif"></div>';
  tmp+='<div onclick="setLang(\'pt\');">portugues <img src="/imgs/lang/pt.gif"></div>';
  langMenu.innerHTML=tmp;

  if (typeof tag != 'undefined'){
    var pos={};
    findPos(tag,pos);
    langMenu.style.top=pos.y+tag.offsetHeight+"px";
    langMenu.style.left=pos.x+tag.offsetWidth/2-langMenu.offsetWidth/2+"px";
  }
}







var sWidth;
var sHeight;

function getWindowSize(){
  if (self.innerWidth)
    { sWidth=self.innerWidth; sHeight=self.innerHeight; }
  else if (document.documentElement && document.documentElement.clientHeight)
    { sWidth = document.documentElement.clientWidth; sHeight = document.documentElement.clientHeight; }
  else if (document.body)
    { sWidth = document.body.clientWidth; sHeight = document.body.clientHeight; }
}



var fps=7.0;
var tpf=1000.0/fps;
//var motionfps=20.0;
//var motiontpf=50.0; //=1000/20.0


// Cross browser event handling for IE 5+, NS6+ and Gecko
function addEvent(elm, evType, fn, useCapture){
  if (elm.addEventListener){
    // Gecko
    elm.addEventListener(evType, fn, useCapture);
    return true;
  } else if (elm.attachEvent){
     // Internet Explorer
    var r = elm.attachEvent('on' + evType, fn);
    return r;
  } else {
    // nutscrape?
    elm['on' + evType] = fn;
  }
}

function removeEvent(elm, evType, fn, useCapture){
  if (elm.removeEventListener){
    // Gecko
    elm.removeEventListener(evType, fn, useCapture);
    return true;
  } else if (elm.detachEvent){
     // Internet Explorer
    var r = elm.detachEvent('on' + evType, fn);
    return r;
  } else {
    // nutscrape?
    elm['on' + evType] = null;
  }
}




var objIntercepts={};
var objInterceptsCount=0;

function objDoIntercept(objIndex,args){
  var obj = objIntercepts[objIndex].obj;
  obj[ objIntercepts[objIndex].hook ].call(obj,objIntercepts[objIndex].method,args);
  return(objIntercepts[objIndex].func.apply(this,args));
}

function objIntercept(obj,method,hook){
  var tmpmethod=method;
  var i=method.indexOf(".");
  var obj2;
  var newIntercept;
  if (i!=-1){
    obj2=method.substr(0,i);
    obj2=obj[obj2];
    method=method.substr(i+1,method.length-i-1);
    newIntercept={obj:obj,hook:hook,obj2:obj2,method:tmpmethod,func:obj2[method]};
    obj2[method]=new Function("return(objDoIntercept.call(this,"+objInterceptsCount+",arguments));");
  }else{
    newIntercept={obj:obj,hook:hook,method:method,func:obj[method]};
    obj[method]=new Function("return(objDoIntercept.call(this,"+objInterceptsCount+",arguments));");
  }

  objIntercepts[objInterceptsCount]=newIntercept;
  objInterceptsCount++;
}




function timer(obj,method,timeout){
  this.t=setTimeout(objCallback(obj,method),timeout);
  //TODO: we have to make sure to free the callback object after the timeout!!, make sure we are not creating continuously more objects for repeated timers!
}

timer.prototype.cancel=function(){
  clearTimeout(this.t);
}


function animation(sceneimg){
  getWindowSize();

  if (typeof images == 'undefined')
    images=new cimages();

  this.vRefpos=new vector;
  this.vScale=new vector(640,480);

  this.doShowSend=false;
  this.mid=0;
  this.movieData={};
  this.movieState=0;
  this.playing=false;
  this.testing=false;
  this.currentFrame=0;
  this.lastFrame=0;
  this.tbLastFrame=50;
  this.dt=0;
  this.balloons={length:0};  //new Array();
  this.actors={length:0}; // new Array();
  this.changes={length:0}; //new Array();

  this.custom={};
  this.customizing=false;

  this.showPrivate=false;
  var args=getArgs();
  if (typeof args["private"]!='undefined')
    this.showPrivate=true;

  this.snow=new Array();


  if (typeof sceneimg != 'undefined'){
    this.scene=new scene(this,sceneimg);
    objIntercept(this,"scene.select","interceptHook");
  }

  this.sound=new csound(this);
  this.sound.init();
  objIntercept(this,"sound.playRec","interceptHook");

  objIntercept(this,"addActor","interceptHook");
  objIntercept(this,"addBalloon","interceptHook");
  objIntercept(this,"deleteActor","interceptHook");
  objIntercept(this,"deleteBalloon","interceptHook");

  this.toolbarMouseDownHandler=objCallback(this,"toolbarMouseDown");
  this.toolbarMouseMoveHandler=objCallback(this,"toolbarMouseMove");
  this.toolbarMouseUpHandler=objCallback(this,"toolbarMouseUp");

  addEvent(window,"resize",objCallback(this,"doResize"),false);

  this.doResize();

  this.onDonePlay=null;
//  this.balloonsLeaveHandler=objCallback(this,"hideBalloons");
}

var curAnimation=null;

animation.prototype.doResize=function(){
  getWindowSize();
  if (typeof this.scene != 'undefined'){
    findPos(this.scene.img,this.vRefpos);
    this.vScale.x = this.scene.img.offsetWidth;
    this.vScale.y = this.scene.img.offsetHeight;
    this.draw();
  }else{
    this.vRefpos.x=0;
    this.vRefpos.y=0;
    this.vScale.x=sWidth;
    this.vScale.y=sHeight;
    this.draw();
  }
}

animation.prototype.hideActors=function(){
  if (this.actorsMenu==null) return;

  document.body.removeChild(this.actorsMenu); 
  this.actorsMenu=null;
}

animation.prototype.showActors=function(type,page){
  if (this.actorsMenu==null){
    var actorsMenu = document.createElement("div");
    this.actorsMenu=actorsMenu;
    document.body.appendChild(actorsMenu);
  }else if (typeof type == 'undefined'){
    this.hideActors();
    return;
  }else{
    actorsMenu=this.actorsMenu;
  }

  this.hideMainMenu();
  this.hideScenes();
  this.hideBalloons();

  if (typeof type == 'undefined') type=0;
  if (typeof page == 'undefined') page=0;

  actorsMenu.style.position="absolute";
  actorsMenu.style.backgroundColor="#fff";
  actorsMenu.style.padding="10px 10px 10px 10px";
  actorsMenu.style.left="100px";
  actorsMenu.style.top="100px";
  actorsMenu.style.width="530px";
  actorsMenu.style.border="1px solid #333";
  actorsMenu.style.zIndex="1010";
  actorsMenu.style.textAlign="left";
//  actorsMenu.style.height="60px";
  actorsMenu.anim=this;

  var appage=20;
  var acount=0;
  var a;
  for (a in actordefs){
    if (a=="indexOf") continue;
    if (actordefs[a].type!=type || !this.showPrivate && actordefs[a].private==1) continue;
    ++acount;
  }

  var astart=page*appage;

  var tmp='<div style="float: right">';
  if (page-1>=0) tmp +='<a href="#" onclick="this.anim.showActors('+type+','+(page-1)+');return(false);">'+L('prev')+'</a> ';
  if (page+1<acount/appage) tmp += '<a href="#" onclick="this.anim.showActors('+type+','+(page+1)+');return(false);">'+L('next')+'</a> ';
  
  tmp += '<a href="#" onclick="this.anim.hideActors();return(false);">'+L('close')+'</a></div>';
  tmp += '<a href="#" onclick="this.anim.showActors(0);return(false);">'+L('actors')+'</a> <a href="#" onclick="this.anim.showActors(1);return(false);">'+L('objects')+'</a> <a href="#" onclick="this.anim.showActors(2);return(false);">'+L('effects')+'</a><br><br>';
  for (var a in actordefs){
    if (a == "indexOf") continue;
    if (actordefs[a].type!=type || !this.showPrivate && actordefs[a].private == 1) continue;


    if (astart>0) { --astart; continue; }
    if (astart==-appage) break;
    --astart; 

    var label;
    if (typeof actorlabels != 'undefined' && typeof actorlabels[a] != 'undefined')
      label=actorlabels[a].label;
    else
      label=a;

    tmp+="<div onclick=\"parentNode.anim.nextTutorial('actor'); parentNode.anim.addActor('"+a+"').setEditable(); parentNode.anim.hideActors(); return(false);\" class=\"actoritem\" onmouseover=\"this.style.backgroundColor='#aaaaff';\" onmouseout=\"this.style.backgroundColor='#ffffff';\"><img onselectstart=\"return(false);\" ondragstart=\"return(false);\" src=\""+getActorDir(a)+"/icon-"+a+"-stand.png\"><br>"+label+"</div>";
  }
  actorsMenu.innerHTML=tmp;

  var res=actorsMenu.getElementsByTagName("a");
  for (var i=0; i<res.length; ++i)
    res[i].anim=this;
}

animation.prototype.showScenes=function(tag){
  this.hideMainMenu();
  this.hideActors();
  this.hideBalloons();

  this.scene.showMenu(tag);
}

animation.prototype.hideScenes=function(){
  this.scene.hideMenu();
}

animation.prototype.showBalloons=function(tag){
  if (this.balloonsMenu!=null){ this.hideBalloons(tag); return(false); }

  this.hideMainMenu();
  this.hideActors();
  this.hideScenes();

//  tag.src = '/imgs/control/down/control11.png';

  var balloonsMenu = document.createElement("div");
  this.balloonsMenu=balloonsMenu;
  document.body.appendChild(balloonsMenu);
  balloonsMenu.style.position="absolute";
  balloonsMenu.style.backgroundColor="#fff";
//  balloonsMenu.style.padding="5px 5px 5px 5px";
  balloonsMenu.style.border="1px solid #333";
  balloonsMenu.style.zIndex="1010";
  balloonsMenu.anim=this;
  tmp='<div style="background-color: #dd3366; text-align: center; color: #fff">Menu</div>';

  balloonsMenu.innerHTML="<div style=\"background-color: #a93; text-align: center; color: #fff\">"+L('Balloons')+"</div><div onclick=\"parentNode.anim.addBalloon('arrow').setEditable(); parentNode.anim.hideBalloons(); return(false);\" onmouseover=\"this.style.backgroundColor='#9999ff';\" onmouseout=\"this.style.backgroundColor='#ffffff';\" style=\"padding-top: 5px; padding-right: 5px\"><img src=\"/imgs/balloon-talk-icon.gif\" style=\"vertical-align: middle; margin-bottom: 5px\"> "+L('Dialog')+"</div><div onclick=\"parentNode.anim.addBalloon('think').setEditable(); parentNode.anim.hideBalloons(); return(false);\" onmouseover=\"this.style.backgroundColor='#9999ff';\" onmouseout=\"this.style.backgroundColor='#ffffff';\" style=\"padding-top: 5px; padding-right: 5px\"><img src=\"/imgs/balloon-think-icon.gif\" style=\"vertical-align: middle; padding-bottom: 5px\"> "+L('Thought')+"</div><div onclick=\"parentNode.anim.addBalloon().setEditable(); parentNode.anim.hideBalloons(); return(false);\" onmouseover=\"this.style.backgroundColor='#9999ff';\" onmouseout=\"this.style.backgroundColor='#ffffff';\" style=\"padding-top: 5px; padding-right: 5px\"><img src=\"/imgs/balloon-narrate-icon.gif\" style=\"vertical-align: middle; padding-bottom: 5px\"> "+L('Narration')+"</div>";
  if (typeof tag != 'undefined'){
    var pos={};
    findPos(tag,pos);
    if (pos.y+tag.offsetHeight+balloonsMenu.offsetHeight < sHeight)
      balloonsMenu.style.top=pos.y+tag.offsetHeight+"px";
    else
      balloonsMenu.style.top=(pos.y-balloonsMenu.offsetHeight)+"px";
    balloonsMenu.style.left=pos.x+tag.offsetWidth/2-balloonsMenu.offsetWidth/2+"px";
  }
//  balloonsMenu.style.left="100px";
//  balloonsMenu.style.top="100px";
//  balloonsMenu.style.width="200px";
//  balloonsMenu.style.height="60px";
//  addEvent(balloonsMenu, 'mousemove', this.balloonsLeaveHandler, false);
}

animation.prototype.hideBalloons=function(tag){
  if (this.balloonsMenu==null) return;

  document.body.removeChild(this.balloonsMenu); 
  this.balloonsMenu=null;
//  tag.src = '/imgs/control/control11.png';
//  curAnimation=null;
}



animation.prototype.toolbarMouseDown=function(e){
  e = e || window.event;

  linfo("got toolbar mousedown");
  addEvent(document, 'mousemove', this.toolbarMouseMoveHandler, false);
  addEvent(document, 'mouseup', this.toolbarMouseUpHandler, false);
  pos={x:0,y:0};
  findPos(this.toolbar.tbTimeline,pos);
  this.seek((e.clientX-pos.x)/(this.toolbar.tbTimeline.offsetWidth-2));
  if (e.stopPropagation){
    linfo("stopped propagation!");
    e.stopPropagation();
    e.preventDefault();
  } else if (typeof e.cancelBubble != 'undefined'){
    linfo("stopped propagation!");
    e.cancelBubble=true;
    e.returnValue=false;
  }
  return(false);
}
animation.prototype.toolbarMouseMove=function(e){
  e = e || window.event;
  pos={x:0,y:0};
  findPos(this.toolbar.tbTimeline,pos);
  this.seek((e.clientX-pos.x)/(this.toolbar.tbTimeline.offsetWidth-2));
  return(false);
}
animation.prototype.toolbarMouseUp=function(e){
  removeEvent(document, 'mousemove', this.toolbarMouseMoveHandler, false);
  removeEvent(document, 'mouseup', this.toolbarMouseUpHandler, false);
}

var tutStep=0;
var tutorialText=null;

var tutorialButton=null;
var tutorialButtonTimer=null;
var tutorialButtonFlag=false;

animation.prototype.flashTutorialButton=function(){
  if (tutorialButton == null) return;

  if (tutorialButtonTimer!=null)
    clearInterval(tutorialButtonTimer);

  tutorialButtonFlag=false;
  imgOver(tutorialButton);
  tutorialButtonTimer=setInterval("if (tutorialButtonFlag) imgOver(tutorialButton); else imgOut(tutorialButton); tutorialButtonFlag=!tutorialButtonFlag;",200.0);

  this.arrow.addActor('arrow','stand');
  this.arrow.actors[0].tag.style.zIndex=2000;
  var pos={};
  findPos(tutorialButton,pos);
  this.arrow.actors[0].moveTo(pos.x+tutorialButton.offsetWidth/2-this.arrow.actors[0].tag.offsetWidth/2,pos.y-this.arrow.actors[0].tag.offsetHeight-10);
  this.arrow.playAnimation();
}
animation.prototype.stopTutorialButton=function(){
  if (tutorialButtonTimer==null) return;

  clearTimeout(this.arrow.timer);
  this.arrow.reset();
  clearInterval(tutorialButtonTimer);
  tutorialButtonTimer=null;
}

animation.prototype.stepTutorial=function(){
  if (tutorialText==null) return;
  if (tutStep>=tutorialText.length) return;

  this.tutor.actors[1].changeDirection();
  this.tutor.balloons[0].setText(tutorialText[tutStep]);
  tutStep++;
  if (tutStep==tutorialText.length && tutorialButton!=null)
    this.flashTutorialButton(); 
  this.tutor.balloons[0].changeDirection();
  this.tutor.balloons[0].pointTo(this.tutor.actors[1].tag);
  this.tutor.playing=true;
  this.tutor.lastTime=new Date();
  this.tutor.currentFrame=0;
  this.tutor.timer=setInterval(""+objTimeout(this.tutor,"playStep"),1000.0/fps);
  this.tutor.playStep();
}

var tutPrevState='';

animation.prototype.nextTutorial=function(type){
  switch (type){
    case 'start':
      if (tutPrevState!='') return;
      tutorialText=new Array(L('Welcome to the Storyboard'),L('Here you can make your own story'),L('First, you need to add actors'),L('Press the flashing button, and choose an actor from the list'));
      tutorialButton=$('actorsMenu');
     break;
    case 'actor':
      if (tutPrevState!='start') return;
      tutorialText=new Array(L('Good! Now you can position your actor by dragging him with the mouse'),L('You can also change the actors action by moving the mouse over the actor'),L('Move the mouse over the actor and choose the walking action now'));
      tutorialButton=null;
     break;
    case 'action':
      if (tutPrevState!='actor') return;
      tutorialText=new Array(L('To make the movie go forward you must click the record button'),L('Click the flashing record button several times'));
      tutorialButton=$('recordButton');
      tutRecordCount=0;
     break;
    case 'record':
      if (tutPrevState!='action') return;
      ++tutRecordCount;
      if (tutRecordCount<5) return;
      tutorialText=new Array(L('Good! Now you can see your movie by clicking the play button'),L('Click on the flashing play button'));
      tutorialButton=$('playButton');
     break;
    case 'main':
      if (tutPrevState!='play') return;
      this.tutorialText=null;
      this.hideTutorial();
      return;
     break;
    case 'play':
      if (tutPrevState!='record') return;
      tutorialText=new Array(L('Very good! Now you know how to make a story'),L('When you are done click the menu button to save and send your story!'));
      tutorialButton=$('mainMenu');
     break;
    case 'recordnoactor':
      tutorialText=new Array(L('You have not added any actor'),L('Click on the flashing actors button to add an actor'));
      tutorialButton=$('actorsMenu');
     break;
    case 'balloon':
      tutorialText=new Array(L('Please record more frames until the balloon count is zero'),L('Only when the count on the balloon is zero can you delete the balloon'));
      tutorialButton=$('recordButton');
     break;
  }
  tutPrevState=type;
  tutStep=0;
  this.stopTutorialButton();
  this.stepTutorial();
}

animation.prototype.hideTutorial=function(){
  if (typeof this.tutor != 'undefined')
    this.tutor.reset();
  this.stopTutorialButton();
}

animation.prototype.showTutorial=function(tag){
  this.hideMainMenu();
  if (typeof this.tutor != 'undefined') return;

  images.loadActorAction('arrow','stand'); 
     
  this.arrow=new animation;
  this.tutor=new animation($('wrapper'));
  this.tutor.editing=false;
  this.tutor.addActor('smoke','stand');
  this.tutor.actors[0].x=1.1;
  this.tutor.actors[0].y=0.55;
  this.tutor.actors[0].draw();
  this.tutor.addActor('dwarf','stand');
  this.tutor.actors[1].changeDirection();
  this.tutor.actors[1].x=1.1;
  this.tutor.actors[1].y=0.55;
  this.tutor.actors[1].draw();
  this.tutor.addBalloon('arrow');
  this.tutor.lastFrame=30;
//  this.tutor.movieData[20]={length:0,actors:{},balloons:{0:{tag:{btext:{innerHTML:"helloo"}}}}};

  this.tutor.onDonePlay=objCallback(this,"stepTutorial");
  this.nextTutorial('start');
}

animation.prototype.send=function(form){
  var sender=form["sender"].value;
  var senderemail=form["senderemail"].value;
  var rcptemails=form["rcptemails"].value;
//  alert("/upload.php?n="+name+"&v="+vis+"&c="+cat+"&email="+email);
//  connPost("/upload.php?n="+name+"&v="+vis+"&c="+cat+"&email="+email,mdata,doneSavedMovie);

  if (sender.length==0)
    { alert(L('Please type in your name')); return(false); }
  if (senderemail.length==0)
    { alert(L("Please type in your email")); return(false); }
  if (rcptemails.length==0)
    { alert(L("Please type in a recipients email address")); return(false); }

  this.hideSend();
  connPost("/send.php?m="+this.mid+"&sender="+sender+"&senderemail="+senderemail,rcptemails);
  alert(L("Cartoon sent!!"));
}


animation.prototype.customize=function(form){
  this.custom={};
  for (var i in this.movieData.custom){
    if (typeof form['custom'+this.movieData.custom[i]].value!='undefined'){
      this.custom[this.movieData.custom[i]]=form['custom'+this.movieData.custom[i]].value;
    }
  }
}

animation.prototype.hideCustom=function(){
  if (this.customMenu==null) return;
  document.body.removeChild(this.customMenu); 
  this.customMenu=null;
}

animation.prototype.showCustom=function(tag){
  if (this.customMenu!=null) return(false);

  var customMenu = document.createElement("div");
  document.body.appendChild(customMenu);

  customMenu.style.textAlign="center";
  customMenu.style.zIndex="1005";
  customMenu.style.position="absolute";
  customMenu.style.border="1px solid #333";
  customMenu.style.padding="10px 10px 10px 10px";
  customMenu.style.backgroundColor="#fff";
  this.customMenu=customMenu;

  var tmp='';
  for (var i in this.movieData.custom){
    var tmpval='';
    if (typeof this.custom[this.movieData.custom[i]] != 'undefined')
      tmpval='value="'+this.custom[this.movieData.custom[i]]+'"';
    tmp+=this.movieData.custom[i]+': <input type="text" name="custom'+this.movieData.custom[i]+'" '+tmpval+'><br/>';
  }
  if (tmp.length>0)
    tmp='<h3>Customize your card</h3>'+tmp;

  customMenu.innerHTML='<div style="background-color: #d36; color: #fff; text-align: center; margin-bottom: 10px">'+L('Customize cartoon')+'</div>'+L('This is a customizable cartoon!<br>Fill in the fields bellow<br>and then click on preview to see how your cartoon will look like')+'<form onsubmit="return(false)">'+tmp+'<input type="submit" name="send" value="'+L('send')+'" style="width: 30%" onclick="this.animation.customize(this.form); this.animation.customizing=false; this.animation.hideCustom(); this.animation.showSend(); return(false);"><input type="submit" name="preview" value="'+L('preview')+'" style="margin-left: 65px; width: 30%" onclick="this.animation.customizing=true; this.animation.customize(this.form); this.animation.hideCustom(); this.animation.play(); return(false);"></form>';
  customMenu.style.left=(sWidth/2-customMenu.offsetWidth/2)+"px";
  customMenu.style.top=(sHeight/2-customMenu.offsetHeight/2)+"px";
  var res=customMenu.getElementsByTagName("input");
  for (i=0; i<res.length; ++i)
    res[i].animation=this;
}

animation.prototype.hideSend=function(){
  if (this.sendMenu==null) return;
  document.body.removeChild(this.sendMenu); 
  this.sendMenu=null;
}

animation.prototype.showSend=function(tag){
  if (this.sendMenu!=null) return(false);

  if (this.lastFrame==0){
    alert(L("Please record your cartoon first"));
    return;
  }else if (this.mid==0){
    alert(L("Please save your cartoon first"));
    this.doShowSend=true;
    this.showSave();
    return;
  }

  var tmp=0;
  for (var i in this.movieData.custom)
    ++tmp;
  if (tmp>0){
    tmp=0;
    for (var i in this.custom)
      ++tmp;
    if (tmp==0){
      this.showCustom();
      this.hideSend();
      return;
    }
  }
 

  this.doShowSend=false;

  this.hideActors();
  this.hideScenes();
  this.hideBalloons();
  this.hideMainMenu();
  this.hideSave();

  var sendMenu = document.createElement("div");
  document.body.appendChild(sendMenu);

  sendMenu.style.textAlign="center";
  sendMenu.style.zIndex="1005";
  sendMenu.style.position="absolute";
  sendMenu.style.border="1px solid #333";
  sendMenu.style.padding="10px 10px 10px 10px";
  sendMenu.style.backgroundColor="#fff";
  this.sendMenu=sendMenu;


  sendMenu.innerHTML='<div style="background-color: #d36; color: #fff; text-align: center; margin-bottom: 10px">'+L('Share cartoon')+'</div>'+L('You can view your cartoon directly at:')+'<br><input type="text" id="savedurl" onclick="this.focus(); this.select();" value="http://www.funtuns.com/ecards/'+this.mid+'" style="width: 95%"><br><br><br>'+L('Or send it by email:')+'<br><br><form name="sendform" onsubmit="this.animation.send(this); return(false);">'+L('Your name:')+' <input type="text" name="sender" value="'+uname+'"><br>'+L('Your email:')+' <input type="text" name="senderemail" value="'+uemail+'"><br><br>'+L('Recipient emails:')+'<br> <input type="text" name="rcptemails" style="width: 95%"><br><div style="text-align: center; width: 100%; margin-top: 20px"><input type="submit" name="send" value="'+L('send')+'" style="width: 30%" ><input type="submit" name="cancel" value="'+L('close')+'" style="margin-left: 65px; width: 30%" onclick="this.animation.hideSend(); return(false);"></div></form>';
  sendMenu.style.left=(sWidth/2-sendMenu.offsetWidth/2)+"px";
  sendMenu.style.top=(sHeight/2-sendMenu.offsetHeight/2)+"px";
  var res=sendMenu.getElementsByTagName("a");
  for (var i=0; i<res.length; ++i)
    res[i].animation=this;
  res=sendMenu.getElementsByTagName("input");
  for (i=0; i<res.length; ++i)
    res[i].animation=this;
  res=sendMenu.getElementsByTagName("form");
  for (i=0; i<res.length; ++i)
    res[i].animation=this;
}

animation.prototype.hideSave=function(){
  if (this.saveMenu==null) return;
  document.body.removeChild(this.saveMenu); 
  this.saveMenu=null;
}

animation.prototype.showSave=function(){
  if (this.lastFrame==0){
    alert(L("You have not recorded anything yet"));
    return;
  }

  if (this.saveMenu!=null) return(false);

  this.hideActors();
  this.hideScenes();
  this.hideBalloons();
  this.hideMainMenu();

  var saveMenu = document.createElement("div");
  document.body.appendChild(saveMenu);

  saveMenu.style.textAlign="center";
  saveMenu.style.zIndex="1005";
  saveMenu.style.position="absolute";
  saveMenu.style.border="1px solid #333";
  saveMenu.style.padding="10px 10px 10px 10px";
  saveMenu.style.backgroundColor="#fff";
  this.saveMenu=saveMenu;

  saveMenu.innerHTML='<div style="background-color: #d36; color: #fff; text-align: center; margin-bottom: 10px">'+L('Save cartoon')+'</div>    <p id="savelogintext">'+L('Please ')+'<a href="#" onclick="this.animation.showLogin(); return(false);">'+L('login')+'</a> '+L('or type in your email')+'<br> '+L('to save this cartoon under your name')+'</p>    <form name="saveform" onsubmit="this.animation.save(this); return(false);" style="text-align: right; margin-right: 5px; margin-bottom: 0px; padding: 0px 0px 0px 0px;">      <div id="savelogin" style="display: none; text-align: right; margin-right: 5px;">'+L('login')+': <input type="text" name="login" value="" size="10" style="width: 6em"> '+L('pass')+': <input type="password" name="pass" value="" size="10" style="width: 6em"><br><small id="saveloginstatus">&nbsp;</small></div>      <p id="saveemail">'+L('email')+': <input type="text" name="email" value=""><br></p>            <div style="text-align: center"><h4>'+L('Cartoon')+'</h4></div>      &nbsp;&nbsp;'+L('title')+': <input type="text" name="name" style="margin-bottom: 12px"><br>      &nbsp;&nbsp;'+L('category')+': <select name="category" style="margin-bottom: 12px">                  <optgroup label="'+L('Cartoon')+'">                    <option value="1">'+L('Funny')+'</option>                    <option value="2">'+L('Short story')+'</option>                    <option value="3">'+L('Fairy tale')+'</option>                  </optgroup>                  <optgroup label="'+L('Ecard')+'">                    <option value="101">'+L('Christmas')+'</option>                    <option value="102">'+L('Birthday')+'</option>                    <option value="103">'+L('Wedding')+'</option>                    <option value="104">'+L('Newborn')+'</option>                    <option value="105">'+L('Party')+'</option>                    <option value="106">'+L('Love')+'</option>                  </optgroup>                </select><br>      visible: <select name="visible" style="margin-bottom: 12px">                <option value="0"> '+L('Public')+'</option>                <option value="1"> '+L('Private')+'</option>               </select>      <div style="clear: both; text-align: center; width: 100%; margin-top: 25px; margin-bottom: 0px; padding: 0px 0px 0px 0px;">      <input type="submit" name="save" value="'+L('save')+'" style="width: 30%"><input type="submit" name="cancel" value="'+L('cancel')+'" style="margin-left: 65px; width: 30%" onclick="this.animation.hideSave(); return(false);">      </div>    </form>';
  saveMenu.style.left=(sWidth/2-saveMenu.offsetWidth/2)+"px";
  saveMenu.style.top=(sHeight/2-saveMenu.offsetHeight/2)+"px";
  var res=saveMenu.getElementsByTagName("a");
  for (var i=0; i<res.length; ++i)
    res[i].animation=this;
  res=saveMenu.getElementsByTagName("input");
  for (i=0; i<res.length; ++i)
    res[i].animation=this;
  res=saveMenu.getElementsByTagName("form");
  for (i=0; i<res.length; ++i)
    res[i].animation=this;
}

animation.prototype.hideMainMenu=function(){
  if (this.mainmenu==null) return;
  document.body.removeChild(this.mainmenu); 
  this.mainmenu=null;
}

animation.prototype.showMainMenu=function(tag){
  if (this.mainmenu!=null) { this.hideMainMenu(); return(false); }

  this.hideActors();
  this.hideScenes();
  this.hideBalloons();

  var menu = document.createElement("div");
  document.body.appendChild(menu);

  menu.style.textAlign="center";
  menu.style.zIndex="1005";
  menu.style.position="absolute";
  menu.style.border="1px solid #333";
  menu.style.backgroundColor="#fff";
  this.mainmenu=menu;

  var tmp="";
  tmp='<div style="background-color: #dd3366; text-align: center; color: #fff">'+L('Menu')+'</div>';
  tmp+='<div style="text-align: left">'
  tmp+='<div onclick="this.animation.showSave(this);" onmouseover="this.style.backgroundColor='+"'#9999ff'"+';" onmouseout="this.style.backgroundColor='+"'#ffffff'"+';" style="padding-top: 5px; padding-right: 5px"><img src="/imgs/menu-save.png" style="vertical-align: middle; margin-bottom: 5px"> '+L('Save cartoon')+'</div>';
  tmp+='<div onclick="this.animation.showSend(this);" onmouseover="this.style.backgroundColor='+"'#9999ff'"+';" onmouseout="this.style.backgroundColor='+"'#ffffff'"+';" style="padding-top: 5px; padding-right: 5px"><img src="/imgs/menu-send.png" style="vertical-align: middle; padding-bottom: 5px"> '+L('Send to friends')+'</div>';
/*  tmp+='<div onclick="this.animation.showTutorial();" onmouseover="this.style.backgroundColor='+"'#9999ff'"+';" onmouseout="this.style.backgroundColor='+"'#ffffff'"+';" style="padding-top: 5px; padding-right: 5px"><img src="/imgs/menu-tutorial.png" style="vertical-align: middle; padding-bottom: 5px"> Start tutorial</div>'; */
  tmp+='</div>';
  menu.innerHTML=tmp;

  if (typeof tag != 'undefined'){
    var pos={};
    findPos(tag,pos);
    if (pos.y+tag.offsetHeight+menu.offsetHeight < sHeight)
      menu.style.top=pos.y+tag.offsetHeight+"px";
    else
      menu.style.top=(pos.y-menu.offsetHeight)+"px";
//    menu.style.top=pos.y+tag.offsetHeight+"px";
    menu.style.left=pos.x+tag.offsetWidth/2-menu.offsetWidth/2+"px";
  }

  var res=menu.getElementsByTagName("div");
  for (var i=0; i<res.length; ++i)
    res[i].animation=this;
}

animation.prototype.showToolbar=function(button){
  if (this.toolbar!=null) return(false);

  var toolbar = document.createElement("div");
  document.body.appendChild(toolbar);

  toolbar.style.textAlign="center";
  toolbar.style.zIndex="1005";
  toolbar.style.position="absolute";
  toolbar.style.left="100px";
  toolbar.style.top="100px";
  toolbar.style.width="321px";
  toolbar.style.height="77px";

/*
  toolbar.style.background="url('/imgs/control.png')";
  toolbar.style.backgroundColor="#9bf";
  toolbar.style.border="1px solid #000";
*/

  toolbar.anim=this;

  this.objReference=objCallbackStr(this);
  var tmpstr=this.objReference;

//  toolbar.innerHTML='<div id="tbTimeline"><div id="tbTimepass"></div></div><a href="#" onclick="a.record(); return(false);">rec</a> <a href="#" onclick="a.play(this); return(false);">play</a><br><a href="#" onclick="this.parentNode.anim.showActors(); return(false);">add actor</a> | <a href="#" onclick="this.parentNode.anim.showBalloons(this); return(false);">add balloon</a> | <a href="#" onclick="this.parentNode.anim.save(); return(false);">save movie</a>';

  toolbar.innerHTML='<div class="tbTimeline"></div><div class="tbTimepass"></div><img src="/imgs/control/timeknob.png" class="tbPosition"><table class="toolbar" width="321" height="77" border="0" cellpadding="0" cellspacing="0"><tr><td colspan="15"><img src="/imgs/control/control01.png" width="321" height="30" alt=""></td></tr><tr><td rowspan="2"><img src="/imgs/control/control02.png" width="18" height="47" alt=""></td><td><img src="/imgs/control/control03.png" onmouseup="imgOver(this)" onmouseover="imgOver(this)" onmousedown="imgDown(this)" onmouseout="imgOut(this)" width="35" height="35" alt=""></td><td rowspan="2"><img src="/imgs/control/control04.png" width="5" height="47" alt=""></td><td><img id="playButton" src="/imgs/control/control05.png" onclick="this.animation.nextTutorial('+"'play'"+'); this.animation.play();" title="'+L('click to play movie')+'" onmouseover="imgOver(this)" onmousedown="imgDown(this)" onmouseup="imgOver(this)" onmouseout="imgOut(this)" width="35" height="35" alt=""></td><td rowspan="2"><img src="/imgs/control/control06.png" width="5" height="47" alt=""></td><td><img id="recordButton" src="/imgs/control/control07.png" title="'+L('click several times to record animation')+'" onclick="this.animation.nextTutorial('+"'record'"+'); this.animation.record();" onmouseover="imgOver(this)" onmousedown="imgDown(this)" onmouseout="imgOut(this)" onmouseup="imgOver(this)" width="35" height="35" alt=""></td><td rowspan="2"><img src="/imgs/control/control08.png" width="23" height="47" alt=""></td><td><img id="actorsMenu" src="/imgs/control/control09.png" title="'+L('add actors')+'" onclick="this.animation.showActors();" onmouseover="imgOver(this)" onmousedown="imgDown(this)" onmouseout="imgOut(this)" onmouseup="imgOver(this)" width="33" height="35" alt=""></td><td rowspan="2"><img src="/imgs/control/control10.png" width="2" height="47" alt=""></td><td><img src="/imgs/control/control11.png" title="'+L('add dialog balloons')+'" onclick="this.animation.showBalloons(this);" onmouseover="imgOver(this)" onmousedown="imgDown(this)" onmouseout="imgOut(this)" onmouseup="imgOver(this)" width="33" height="35" alt=""></td><td rowspan="2"><img src="/imgs/control/control12.png" width="2" height="47" alt=""></td><td><img src="/imgs/control/control13.png" title="'+L('change the scene')+'" onclick="this.animation.showScenes(this);" onmouseover="imgOver(this)" onmousedown="imgDown(this)" onmouseout="imgOut(this)" onmouseup="imgOver(this)" width="33" height="35" alt=""></td><td rowspan="2"><img src="/imgs/control/control14.png" width="2" height="47" alt=""></td><td><img id="mainMenu" src="/imgs/control/control15.png" title="'+L('main menu: save your cartoon and send it to friends')+'" onclick="this.animation.nextTutorial('+"'main'"+'); this.animation.showMainMenu(this); return(false);" onmouseover="imgOver(this)" onmousedown="imgDown(this)" onmouseout="imgOut(this)" onmouseup="imgOver(this)" width="33" height="35" alt=""></td><td rowspan="2"><img src="/imgs/control/control16.png" width="27" height="47" alt=""></td></tr><tr><td><img src="/imgs/control/control17.png" width="35" height="12" alt=""></td><td><img src="/imgs/control/control18.png" width="35" height="12" alt=""></td><td><img src="/imgs/control/control19.png" width="35" height="12" alt=""></td><td><img src="/imgs/control/control20.png" width="33" height="12" alt=""></td><td><img src="/imgs/control/control21.png" width="33" height="12" alt=""></td><td><img src="/imgs/control/control22.png" width="33" height="12" alt=""></td><td><img src="/imgs/control/control23.png" width="33" height="12" alt=""></td></tr></table>';

  var res=toolbar.getElementsByTagName("div"); 
  toolbar.tbTimeline=res[0];
//  alert(toolbar.tbTimeline+" --- " +
  toolbar.tbTimepass=res[1];
  toolbar.tbPosition=toolbar.getElementsByTagName("img")[0];
  var res=toolbar.getElementsByTagName("img");
  for (var i=0; i<res.length; ++i){
    linfo("images: "+i);
    res[i].onselectstart=function(){return(false);}
    res[i].ondragstart=function(){return(false);}
    res[i].animation=this;
  }
  setMovable(toolbar);

//  toolbar.tbTimeline.onmousedown=toolbarMouseDown;
  addEvent(toolbar.tbPosition, 'mousedown', this.toolbarMouseDownHandler, true);
  addEvent(toolbar.tbTimeline, 'mousedown', this.toolbarMouseDownHandler, true);
  addEvent(toolbar.tbTimepass, 'mousedown', this.toolbarMouseDownHandler, true);

  images.loadActors();
  this.toolbar=toolbar;
}

function getArgument(arg){
  switch (typeof arg){
    case 'string':return("'"+arg+"'");
    case 'number':return(arg);
    case 'boolean':if(arg) return('true'); else return('false');
   default:
    lerror("unhandled type: "+typeof arg);
  }
  return("error");
}

animation.prototype.interceptHook=function(method,args){
  if (this.playing) return;

  var tmp=method+"(";
  for (var i=0; i<args.length; ++i)
    tmp+=getArgument(args[i])+",";
  if (args.length>0)
    tmp=tmp.substr(0,tmp.length-1)+")";
  else
    tmp+=")";
  this.changes[this.changes.length]=tmp;
  this.changes.length++;
//  alert(tmp);
}

function hasChanges(changes){
  if (changes.length>0) return(true);
  for (var i in changes){
    if (i == 'length') continue;
    return(true);
  }
  return(false);
}

function execChange(obj,cmd){
  currentObj=obj;
  eval("currentObj."+cmd);
}

var currentObj;

function makeChanges2(obj,changes){
  if (typeof obj=='undefined' || typeof changes=='undefined') return;

  var i;
  for (i in changes){
    if (parseInt(i)==i)
      execChange(obj,changes[i]);
    else if (typeof obj[i] == 'number' || typeof obj[i] == 'string')
      obj[i]=changes[i];
  }
//  alert("changes: "+changes.length);
//  for (i=0; i<changes.length; ++i){
//    alert("this."+changes[i]);
//    eval("this."+changes[i]);
//  }
}
function makeChanges(obj,changes){
  if (typeof obj=='undefined' || typeof changes=='undefined') return;

  var i;
  for (i in changes){
    if (parseInt(i)==i)
      execChange(obj,changes[i]);
    else if (typeof obj[i] == 'number' || typeof obj[i] == 'string')
      obj[i]=changes[i];
    else if (typeof obj[i] == 'object' && typeof changes[i] == 'object')
      makeChanges(obj[i],changes[i]);
  }
//  alert("changes: "+changes.length);
//  for (i=0; i<changes.length; ++i){
//    alert("this."+changes[i]);
//    eval("this."+changes[i]);
//  }
}

document.ondragstart=function(){ return(false); }
document.ondragselect=function(){ return(false); }

animation.prototype.resetKeyFrame=function(){
  this.changes.actors={};
  for (var i in this.actors){
    if (parseInt(i)!=i) continue;
    this.actors[i].changes={};
  }
  this.changes.balloons={};
  for (var i in this.balloons){
    if (parseInt(i)!=i) continue;
    this.balloons[i].changes={};
  }
  this.changes={length:0};
}

animation.prototype.saveKeyFrame=function(){
  this.changes.actors={};
  for (var i in this.actors){
    if (parseInt(i)!=i) continue;
    if (hasChanges(this.actors[i].changes)){
      this.changes.actors[i] = this.actors[i].changes;
      this.actors[i].changes={};
    }
  }
  this.changes.balloons={};
  for (var i in this.balloons){
    if (parseInt(i)!=i) continue;
    if (hasChanges(this.balloons[i].changes)){
      this.changes.balloons[i] = this.balloons[i].changes;
      this.balloons[i].changes={};
    }
  }
  if (this.changes.length>0 || hasChanges(this.changes.actors) || hasChanges(this.changes.balloons)){
    this.movieData[this.currentFrame]=this.changes;
    this.changes={length:0};
  }
}

animation.prototype.loadKeyFrame=function(frame){
  if (!(frame in this.movieData)) return;

  var keyFrame=this.movieData[frame];

  var i;
  makeChanges2(this,keyFrame);

  makeChanges2(this.scene,keyFrame.scene);
  for (i in keyFrame.actors){
    if (parseInt(i)!=i || !(i in this.actors) ) continue;
    makeChanges(this.actors[i],keyFrame.actors[i]);
    this.actors[i].draw();
  }
  for (i in keyFrame.balloons){
    if (parseInt(i)!=i) continue;
    makeChanges(this.balloons[i],keyFrame.balloons[i]);
    this.balloons[i].draw();
  }
}

function serialize2(obj){
  var str="";
  var i;
  switch(typeof obj){
    case 'string':
      str+='"'+obj+'"';
     break;
    case 'number':
      str+=obj;
     break;
    case 'array':
      str+="[";
      for (i=0; i<obj.length; ++i)  
        str+=serialize2(obj[i])+",";
      for (i in obj)
        str+=i+":"+serialize2(obj[i])+",";
      if (str.length>1)
        str=str.substr(0,str.length-1)+"]";
      else
        str+="]";
     break;
    case 'object':
      str+="{";
      for (i in obj)
        str+=i+":"+serialize2(obj[i])+",";
      if (str.length>1)
        str=str.substr(0,str.length-1)+"}";
      else
        str+="}";
     break;
    case 'boolean':
      if (obj) str+='true';
      else str+='false';
     break;
    default:
      lerror("serialize: unhandled type: "+typeof obj);
  }
  return(str);
}

animation.prototype.doneSavedMovie=function(data){
  this.mid=data;
  alert(L("Your cartoon was saved!"));
//  if (this.doShowSend)
  this.showSend();
  removeExitAlert();
}

animation.prototype.save=function(form){
  this.movieData.lastFrame=this.lastFrame;
  this.movieData.sndid=this.sndid;
  var mdata=serialize2(this.movieData);

//  alert(mdata);
  var email=form["email"].value;
  var name=form["name"].value;
  var cat=form["category"].value;
  var vis=form["visible"].value;

  if (name.length==0)
    { alert(L('Please type in a title for your cartoon')); return(false); }

  connPost("/upload.php?n="+name+"&v="+vis+"&c="+cat+"&email="+email,mdata,objCallback(this,"doneSavedMovie"));
  this.hideSave();
}

animation.prototype.doneLoadingImages=function(){
//  alert("done loading images!!");
  delete images.onLoaded[this.doneLoadingImagesCallback];
  this.play();
}

animation.prototype.doneLoadingMovie=function(data){
//  alert("done loading movie: "+data.length+" data: "+data);
  eval("this.movieData="+data);
  this.lastFrame=this.movieData.lastFrame;
  this.sndid=this.movieData.sndid;
  this.testPlay();
  this.doneLoadingImagesCallback=images.onLoadedAdd(objCallback(this,"doneLoadingImages"));
  images.loadOnly(this.imgsList);
  if (!images.loading)
    this.play();
}
animation.prototype.load=function(mid,action){
//  curAnimation=this;

  if (this.playing){
    clearInterval(this.timer);
    this.playing=false;
  }

  this.mid=mid;
  connGet("/movie.php?movie="+mid,objCallback(this,"doneLoadingMovie"));
}

animation.prototype.testPlay=function(){
  this.testing=true;
  this.playing=true;
  this.currentFrame=0;
  this.imgsList={};
  this.reset();
  for (var i=0; i<this.lastFrame; i++){
    this.loadKeyFrame(i);
    this.update();
    this.testDraw();
  }
  this.reset();
  this.testing=false;
  this.playing=false;
}

animation.prototype.playAnimation=function(){
  if (this.playing){
    clearInterval(this.timer);
  }
  this.playing=true;
  this.lastTime=new Date();
  this.currentFrame=0;
  this.timer=setInterval(""+objTimeout(this,"playStepAnimation"),1000.0/fps);
  this.playStepAnimation();
}
animation.prototype.playStepAnimation=function(){
  var curTime=new Date();
  
  this.dt+=curTime-this.lastTime;
  this.lastTime=curTime;
  
  while(this.dt > tpf){
    this.dt -= tpf;
    this.update();
  }

//  this.sortActors();
  this.draw();
}

animation.prototype.play=function(){
  if (this.playing)
    clearInterval(this.timer);
  this.playing=true;
  this.lastTime=new Date();
  this.currentFrame=0;
  this.reset();
  this.loadKeyFrame(0);
  this.timer=setInterval(""+objTimeout(this,"playStep"),1000.0/fps);
  this.playStep();
}

animation.prototype.playStep=function(){
  var curTime=new Date();
  
  this.dt+=curTime-this.lastTime;
  this.lastTime=curTime;
  
  while(this.dt > tpf){
    this.dt -= tpf;

    ++this.currentFrame;
    this.update();
    if (this.currentFrame>=this.lastFrame)
      this.currentFrame=this.lastFrame;
    this.loadKeyFrame(this.currentFrame);
  }

  this.sortActors();
  this.draw();
 
//  $('frame').innerHTML = this.currentFrame;

  if (this.currentFrame>=this.lastFrame){
    clearInterval(this.timer);
    this.resetKeyFrame();
    this.playing=false;
    if (this.toolbar!=null){
      this.setEditable();
      ++this.currentFrame; // should be 1 more than the last frame to avoid overwriting the last frame
      this.recordUpdateSeek();
      return;
    }
    if (this.onDonePlay!=null && !this.customizing)
      this.onDonePlay();
    if (this.customizing)
      this.showCustom();
  }
/*
  if (this.currentFrame<this.lastFrame)
    this.timer=new timer(this,"playStep",50);   
  else
    this.playing=false;
*/
  if (typeof this.timePass != 'undefined' && this.timePass != null){
    this.timePass.style.width=Math.floor(this.currentFrame * (this.timeLine.offsetWidth-2) / this.lastFrame)+"px";
    this.timePosition.style.left=Math.floor(this.currentFrame * (this.timeLine.offsetWidth-2) / this.lastFrame)+"px";
  }
  if (this.toolbar!=null){
    this.toolbar.tbTimepass.style.width=Math.floor(this.currentFrame * (this.toolbar.tbTimeline.offsetWidth-2) / this.lastFrame)+"px";
    this.toolbar.tbPosition.style.left=Math.floor(15+this.currentFrame * (this.toolbar.tbTimeline.offsetWidth-2) / this.lastFrame)+"px";
  }
}

animation.prototype.updateBalloonCount=function(){
  for (var i in this.balloons){
    if (parseInt(i)!=i) continue;
    if (parseInt(this.balloons[i].tag.count.innerHTML)>0)
       this.balloons[i].tag.count.innerHTML=parseInt(this.balloons[i].tag.count.innerHTML)-1;
  }
}

animation.prototype.setEditable=function(){
  for (var i in this.actors){
    if (parseInt(i)!=i) continue;
    this.actors[i].setEditable();
  }
  for (var i in this.balloons){
    if (parseInt(i)!=i) continue;
    this.balloons[i].setEditable();
  }
}

animation.prototype.recordUpdateSeek=function(){
  if (this.lastFrame/this.tbLastFrame >= 1.0)
    this.tbLastFrame=Math.floor(this.lastFrame/0.60);

  if (typeof this.timePass != 'undefined' && this.timePass!=null){
    this.timePass.style.width=Math.floor(this.currentFrame * (this.timeLine.offsetWidth-2) / this.lastFrame)+"px";
    this.timePosition.style.left=Math.floor(this.currentFrame * (this.timeLine.offsetWidth-2) / this.lastFrame)+"px";
  }
  if (this.toolbar!=null){
    this.toolbar.tbTimepass.style.width=Math.floor(this.currentFrame * (this.toolbar.tbTimeline.offsetWidth-2) / this.tbLastFrame)+"px";
    this.toolbar.tbPosition.style.left=Math.floor(15+this.currentFrame * (this.toolbar.tbTimeline.offsetWidth-2) / this.tbLastFrame)+"px";
  }
//  $('frame').innerHTML = this.currentFrame;
}

animation.prototype.record=function(){
  addExitAlert();
  this.saveKeyFrame();
  if (this.lastFrame<=this.currentFrame)this.lastFrame=this.currentFrame;
  ++this.currentFrame;
  this.update();
  this.updateBalloonCount();
  this.draw();
  this.recordUpdateSeek();
}

animation.prototype.reset=function(){
  for (var i in this.actors){
    if (parseInt(i)!=i) continue;
    this.deleteActor(parseInt(i));
  }
  this.actors.length=0;
  for (var i in this.balloons){
    if (parseInt(i)!=i) continue;
    this.deleteBalloon(parseInt(i));
  }
  this.balloons.length=0;
  this.resetKeyFrame();
}

animation.prototype.seek=function(value){
  var seekFrame=Math.floor(this.lastFrame*value);
  if (seekFrame>=this.lastFrame) seekFrame=this.lastFrame;
  if (seekFrame<0) seekFrame=0;

//  this.testing=true;
  this.playing=true;
  this.reset();
  for (var i=0; i<seekFrame; i++){
    this.loadKeyFrame(i);
    this.update();
  }
  this.currentFrame=seekFrame;
  
  this.toolbar.tbTimepass.style.width=Math.floor(this.currentFrame * (this.toolbar.tbTimeline.offsetWidth-2) / this.lastFrame)+"px";
  this.toolbar.tbPosition.style.left=Math.floor(15+this.currentFrame * (this.toolbar.tbTimeline.offsetWidth-2) / this.lastFrame)+"px";
//  $('frame').innerHTML = this.currentFrame;
  this.sortActors();
  this.draw();
//  this.testing=false;
  this.playing=false;
  this.setEditable();
}

animation.prototype.addBalloon=function(type){
  var newballoon=new balloon(this,type);

  newballoon.index=this.balloons.length;
  this.balloons[this.balloons.length]=newballoon;
  this.balloons.length++;
  return(newballoon);
}
animation.prototype.deleteBalloon=function(index){
  if (typeof index != "number")
    index=this.getBalloonIndex(index);

  if (index<0 || index>=this.balloons.length) { lerror("trying to delete balloon out of bounds"); return; }

  if (!(index in this.balloons)) return;

  this.balloons[index].remove();
  delete this.balloons[index];
}


animation.prototype.addSnow=function(){
  var newsnow=new snow(this);

  this.snow[this.snow.length]=newsnow;
  newsnow.draw();
  return(newsnow);
}

// function(a1,a2,loop,px,py,s)
animation.prototype.addActor=function(type,action,loop,px,py,s){
  var newactor=new actor(this,type);

  if (typeof action != 'undefined')
    newactor.action=action;
  if (typeof px != 'undefined')
    newactor.x=px;
  if (typeof py != 'undefined')
    newactor.y=py;
  if (typeof s != 'undefined')
    newactor.scale=s;

  newactor.draw();

  newactor.index=this.actors.length;
  this.actors[this.actors.length]=newactor;
  this.actors.length++;
  if (!this.testing && !this.playing){
    images.loadActorActions(type);
    images.loadActorAction(type,newactor.action); 
  }
  return(newactor);
}

animation.prototype.getActorIndex=function(actor){
  for (var i in this.actors)
    if (actor==this.actors[i]) return(parseInt(i));
  lerror("actor not found");
  return(null);
}
animation.prototype.getBalloonIndex=function(balloon){
  for (var i in this.balloons)
    if (balloon==this.balloons[i]) return(i);
  return(null);
}


animation.prototype.deleteActor=function(index){
  if (typeof index != "number")
    index=this.getActorIndex(index);

  if (index<0 || index>=this.actors.length) { lerror("trying to delete actor out of bounds"); return; }

  if (!(index in this.actors)) return;

  this.actors[index].remove();
  delete this.actors[index];
}

animation.prototype.update=function(){
  var i;

  for (i in this.actors){
    if (parseInt(i) != i) continue;
    this.actors[i].update();
  }
}

animation.prototype.testDraw=function(){
  var i;
  for (i in this.actors){
    if (parseInt(i) != i) continue;
    this.actors[i].testDraw();
  }
}

animation.prototype.draw=function(){
  var i;
  for (i in this.actors){
    if (parseInt(i) != i) continue;
    this.actors[i].draw();
  }
  for (i in this.balloons){
    if (parseInt(i) != i) continue;
    this.balloons[i].draw();
  }
}

animation.prototype.sortActors=function(){
  if (this.actors.length<=1) return;
  
  var tmparr=new Array();
//  tmparr[0]=0;
  for (var i in this.actors){
    if (parseInt(i)!=i) continue;
    for (var j=0; j<tmparr.length; ++j){
      if (this.actors[i].tag.offsetTop+this.actors[i].tag.offsetHeight < this.actors[tmparr[j]].tag.offsetTop+this.actors[tmparr[j]].tag.offsetHeight){
        for (var k=tmparr.length; k>j; --k)
          tmparr[k]=tmparr[k-1];
        tmparr[j]=i;
        break;
      }
    }
    if (j==tmparr.length)
      tmparr[j]=i;
  }
  for (var i=0; i<tmparr.length; ++i){
    this.actors[tmparr[i]].tag.style.zIndex=i+this.actors[tmparr[i]].z;
  }
}

animation.prototype.playActor=function(a1,a2,loop,px,py,s){
  if (this.playing){ clearInterval(this.timer); }

  this.actorFrame=0;
  this.actorType=a1;
  this.actorAction=a2;
  this.actorLoop=loop;
  this.actorX=px;
  this.actorY=py;
  this.actorS=s;
  this.playing=true;
  images.loadActor(a1);
  images.loadActorAction(a1,a2);
  this.reset();
  var newActor=this.addActor(a1);
  newActor.action=a2;

  this.playActorStep();

  this.CBplayActor=objTimeout(this,"playActorStep");
  this.timer=setInterval(""+this.CBplayActor,1000/fps);  //new timer(this,"playActorStep",1000/fps);
}
animation.prototype.stopActor=function(){
  if (this.playing){ clearInterval(this.timer); }
  this.playing=false;
}
animation.prototype.playActorStep=function(){
  this.showActor(this.actorType,this.actorAction,this.actorFrame,this.actorX,this.actorY,this.actorS);
  this.actorFrame++;
//  if (!this.playing || !(this.actorLoop || this.actorFrame < 3*actordefs[this.actorType].actions[this.actorAction].frames))
//    this.stopActor();
//    this.timer=setTimeout(""+this.CBplayActor,1000/fps);  //new timer(this,"playActorStep",1000/fps);
}
animation.prototype.showActor=function(a1,a2,frame,ax,ay,as){
//  images.loadActor(a1);
//  images.loadActorAction(a1,a2);

  var newActor;

  newActor=this.actors[0];
  if (a2 in actordefs[a1].actions){
    if (actordefs[a1].actions[a2].frames==0){
      newActor.x=ax;
      newActor.y=ay;
      newActor.scale=as;
//      newActor.action=a2;
      newActor.draw();
      this.stopActor();
//      this.actors[0].action=a2;
//      this.actors[0].draw();
    }else{
//      newActor=this.addActor(a1);
//      newActor.action=a2;
//      for (var j=0; j<frame; ++j)
        newActor.update();
      if (newActor.action != this.actorAction)
        images.loadActorAction(newActor.type,newActor.action);
      newActor.x=ax;
      newActor.y=ay;
      newActor.scale=as;
      newActor.draw();
    }
  }
}




animation.prototype.playActorSequence=function(a1,a2,a3){
  this.actorFrame=0;
  this.actorType=a1;
  this.actorAction=a2;
  this.playing=true;
  images.loadActor(a1);
  images.loadActorAction(a1,a2);
  this.actorLoop=false;
  if (typeof a3 != 'undefined' && a3==true)
    this.actorLoop=true;
  this.playActorSequenceStep();
}

animation.prototype.playActorSequenceStep=function(){
  this.showActorSequence(this.actorType,this.actorAction,this.actorFrame,1);
  this.actorFrame++;
  if (this.playing && (this.actorLoop || this.actorFrame < 3*actordefs[this.actorType].actions[this.actorAction].frames))
    this.timer=new timer(this,"playActorSequenceStep",1000/fps);
}

animation.prototype.showActorSequence=function(a1,a2,frame,transp){
  var maxTransp=0.5;

  this.reset();

  if (a2 in actordefs[a1].actions){
    if (actordefs[a1].actions[a2].frames==0){
      this.addActor(a1);
      this.actors[0].action=a2;
      this.actors[0].draw();
    }else{
      var lastframe=actordefs[a1].actions[a2].frames;
      var i=frame-transp;
      if (frame+transp<lastframe) lastframe=frame+transp+1;
      if (i<0) i=0;

      var newActor;
      for (; i<frame; ++i){
        newActor=this.addActor(a1);
        newActor.action=a2;
        for (var j=0; j<i; ++j)
          newActor.update();
        newActor.tag.style.opacity=maxTransp*(i-frame+transp+1)/(transp+1);
        newActor.draw();
      }
      newActor=this.addActor(a1);
      newActor.action=a2;
      for (var j=0; j<i; ++j)
        newActor.update();
      newActor.tag.style.opacity=1.0;
      newActor.draw();
      ++i;
/*
      for (; i<lastframe; ++i){
        newActor=this.addActor(a1);
        newActor.action=a2;
        for (var j=0; j<i; ++j)
          newActor.update();
        newActor.tag.style.opacity=maxTransp*(frame+transp+1-i)/(transp+1);
        newActor.draw();
      }
*/
    }
  }
}





var consoleText="";
var consoleActive=false;
var console;

function initConsole(){
// alert("creating element");

  console = document.createElement("div");
  document.body.appendChild(console);
//  console=document.getElementById("console");
  console.style.position="absolute";
  console.style.left=(sWidth-220)+"px";
  console.style.top=(sHeight-400)+"px";
  console.style.width="300px";
  console.style.height="200px";
  console.style.backgroundColor="#fff";
  console.style.border="1px solid #333";
  console.style.padding="10px 10px 10px 10px";
//  console.style.display="none";
//  console.style.visibility=true;

  consoleActive=true;

  updateConsole();
}


function updateConsole(){
  if (!consoleActive) return;
  if (typeof console=='undefined') return;
  console.innerHTML="<h3>Console:</h3><br>"+consoleText;
}

function lerror(errormsg){
  if (!consoleActive) return;
  consoleText="error: "+errormsg+"<br>"+consoleText;
  updateConsole();
}
function lwarn(warnmsg){
  if (!consoleActive) return;
  consoleText="warning: "+warnmsg+"<br>"+consoleText;
  updateConsole();
}
function linfo(infomsg){
  if (!consoleActive) return;
  consoleText="info: "+infomsg+"<br>"+consoleText;
  updateConsole();
}



var objCallbacks={};
var objCallbacksCount=0;

function objCallback(obj,method){
  objCallbacks[objCallbacksCount]=obj;
  var f=new Function("return( objCallbacks["+objCallbacksCount+"]['"+method+"'].apply(objCallbacks["+objCallbacksCount+"],arguments));");
  objCallbacksCount++;
  return(f);
}
function objCallbackStr(obj,method){
  objCallbacks[objCallbacksCount]=obj;
  var str="objCallbacks["+objCallbacksCount+"]";
  objCallbacksCount++;
  return(str);
}
function objCallbackRemove(obj){
  for (var i in objCallbacks){
    if (objCallbacks[i]==obj)
      delete objCallbacks[i];
  }
}
function objTimeout(obj,method){
  objCallbacks[objCallbacksCount]=obj;
  var f="objCallbacks["+objCallbacksCount+"]['"+method+"'].apply(objCallbacks["+objCallbacksCount+"]);";
  objCallbacksCount++;
  return(f);
}








function moveObjectMMove(e){
  e=e||window.event;
  this.style.left = (this.movStartObjectX + e.clientX - this.movStartX)+"px";
  this.style.top = (this.movStartObjectY + e.clientY - this.movStartY)+"px";
  return(false);
}

function moveObjectMDown(e)
{
  linfo("got moveObject mousedown");
  e=e||window.event;

  this.movStartX = e.clientX; this.movStartY = e.clientY;
  this.movStartObjectX = this.offsetLeft;
  this.movStartObjectY = this.offsetTop;
  
  this.onmousemove=moveObjectMMove;
  addEvent(document,'mousemove',this.onmousemoveCallback,false);
  addEvent(document,'mouseup',this.onmouseupCallback,false);

  return(false);
}

function moveObjectMUp(e)
{
  e=e||window.event;
  this.onmousemove=null;
  removeEvent(document,'mousemove',this.onmousemoveCallback,false);
  removeEvent(document,'mouseup',this.onmouseupCallback,false);
  return(false);
}

function setMovable(obj)
{
  obj.onmouseupCallback=objCallback(obj,"onmouseup");
  obj.onmousemoveCallback=objCallback(obj,"onmousemove");

  obj.onmousedown=moveObjectMDown;
  obj.onmouseup=moveObjectMUp;
}

function UIsaveShowLogin(){
  document.getElementById("savelogin").style.display='block';
}

function doneCheckLogin(data){
  if (data!="0"){
    document.getElementById("saveloginstatus").innerText="login successful";
    document.getElementById("saveloginstatus").style.color="#0f0";
    uid=data;
    saveCartoon();
    return;
  }
  document.getElementById("saveloginstatus").innerText="wrong user/password, try again";
  document.getElementById("saveloginstatus").style.color="#f00";
}

function UIcheckLogin(){
  var user=document.forms['saveform'].login.value;
  var pass=document.forms['saveform'].pass.value;
  connPost("/checklogin.php","login=1&username="+user+"&password="+pass,doneCheckLogin);
  return(false);
}

function UIalert(message,nfunc)
{
  document.getElementById('a_message').innerText=message;
  if (typeof nfunc != 'undefined')
    document.getElementById('a_ok').onclick=function(){ nfunc(); UIhideDialog('alert'); return(false); }
  else
    document.getElementById('a_ok').onclick=function(){ UIhideDialog('alert'); return(false); }
  
  UIshowDialog('alert');
//  alert(message);
//  nfunc();
}


var menuTimeouts={};

function UIshowMenu(menu,tag){
  if (typeof menuTimeouts[menu] != 'undefined')
    clearTimeout(menuTimeouts[menu]);

  var pos={};
  findPos(tag,pos);

  var UImenu = document.getElementById(menu+"menu");
  UImenu.style.visibility="visible";
  if (pos.x+UImenu.offsetWidth>sWidth)
    UImenu.style.left=(sWidth-UImenu.offsetWidth-20)+"px";
  else
    UImenu.style.left=pos.x+"px";
  if (pos.y+UImenu.offsetHeight>sHeight)
    UImenu.style.top=(sHeight-UImenu.offsetHeight)+"px";
  else
    UImenu.style.top=(pos.y+tag.offsetHeight)+"px";
  UImenu.onmouseover=function(){ UIshowMenu(menu); }
  UImenu.onmouseout=function(){ UIhideMenu(menu); }
/*  document.getElementById(menu+"icon").style.opacity="1.0"; */
}

function UIhideMenu(menu,now){
  if (typeof now == 'undefined'){
    if (typeof menuTimeouts[menu] != 'undefined')
      clearTimeout(menuTimeouts[menu]);
    menuTimeouts[menu] = setTimeout("UIhideMenu('"+menu+"',true);",500);
    return;
  }
  document.getElementById(menu+"menu").style.visibility="hidden";
/*  document.getElementById(menu+"icon").style.opacity="0.6"; */
}


/*
function UIloadMusics(){
  var UImusics=document.getElementById("musics");

  var tmp="";  
  for (a in musicdefs){
    if (a == "indexOf") continue;
    tmp+="<div ondragstart=\"return(false);\" onselectstart=\"return(false);\" onclick=\"UIchangeMusic('"+a+"');\" onmouseover=\"this.style.backgroundColor='#aaaaff';\" onmouseout=\"this.style.backgroundColor='#ffffff';\" style=\"padding-top: 5px; padding-right: 5px\"><img src=\"/imgs/music-item.png\" style=\"vertical-align: middle; margin-bottom: 5px\"> "+a+"</div>";
  }

  UImusics.innerHTML=tmp;
}
*/

/*
function hideUIcontrol(){
  document.getElementById("controls").style.visibility='hidden';
  ballooneditor.style.display="none";
  editingBalloon=false;
}

function showUIcontrol(){
  document.getElementById("controls").style.visibility='visible';
}
*/

function UIshowDialog(name){
  var UIdialog = document.getElementById(name+"dialog");
  UIdialog.style.display='block';
  UIdialog.style.left=(sWidth/2-parseInt(UIdialog.offsetWidth)/2)+"px";
  UIdialog.style.top=(sHeight/2-parseInt(UIdialog.offsetHeight)/2)+"px";
}

function UIhideDialog(name){
  document.getElementById(name+"dialog").style.display="none";
}

function UIshowSave(){
  if (uid!=0){
    document.getElementById('savelogintext').style.display='none';
    document.getElementById('saveemail').style.display='none';
  }
  UIshowDialog('save');
}

function UIshowSend(){
  if (saved.length==0){
    UIalert("You need to save your cartoon first",UIshowSave);
    return;
/*
  }else if (uid==0){
    UIshowDialog("register");
    return;
*/
  }
  document.forms['sendform'].senderemail.value=uemail;
  document.getElementById("savedurl").value="http://www.funtuns.com/cartoons/"+saved;
  UIshowDialog("send");
}

var ctrlMod=false;

function doKeyDown(e){
  if (ctrlMod==true || editingBalloon==true) return(true);

  var e;
  var code;
  e = e || window.event;

  //Find Which key is pressed
  if (e.keyCode) code = e.keyCode;
  else if (e.which) code = e.which;
  
  if (BrowserDetect.browser=="Safari" && code==91)
    { ctrlMod=true; return(true); }
  if (BrowserDetect.browser=="Firefox" && code==224)
    { ctrlMod=true; return(true); }

  if (code==32 && movieControl==0){
    movieControl=100;
    dt=tpf;
    lastTime=new Date();
    return(false);
  }
  if (code==32)
    return(false);
  
  return(true);
}

function doKeyUp(e){
  if (editingBalloon==true) return(true);
  
  var e;
  var code;
  e = e || window.event;

  //Find Which key is pressed
  if (e.keyCode) code = e.keyCode;
  else if (e.which) code = e.which;
  
  if (BrowserDetect.browser=="Safari" && code==91)
    { ctrlMod=false; return(true); }
  if (BrowserDetect.browser=="Firefox" && code==224)
    { ctrlMod=false; return(true); }
    
  if (ctrlMod==true) return(true);

  if (code==32){
    movieControl=0;
    return(false);
  }  
    
  return(true);
}

var tutorialStep=0;

function startTutorial(){
  tutorialStep=0;
  document.getElementById("tutorialSkip").value=tutorialSkipLabel; // "skip tutorial"
  UItutorialNextStep();
  UIshowDialog("tutorial");
}

function UItutorialNextStep(){
  var UItutorial = document.getElementById("tutorialtext");
  var UItutTitle = document.getElementById("tutorialTitle");
  ++tutorialStep;
  
  if (tutorialSteps.length>tutorialStep){
/*
   if (tutorialStep>1 && "highlight" in tutorialSteps[tutorialStep-1]){
      var tmparr=tutorialSteps[tutorialStep-1].highlight.split(",");
      for (var i=0;i<tmparr.length; ++i)
        document.getElementById(tmparr[i]).style.border="";
    }    
    if ("highlight" in tutorialSteps[tutorialStep]){
      var tmparr=tutorialSteps[tutorialStep].highlight.split(",");
      for (var i=0;i<tmparr.length; ++i)
        document.getElementById(tmparr[i]).style.border="3px solid #ff0";
    }
*/
    UItutTitle.innerHTML = tutorialSteps[tutorialStep].title;
    UItutorial.innerHTML = tutorialSteps[tutorialStep].text;
  }else
    UIhideDialog("tutorial");
    
  if (tutorialSteps.length-1==tutorialStep)
    document.getElementById("tutorialNext").value=tutorialFinishLabel; //"finish";
  else
    document.getElementById("tutorialNext").value=tutorialNextLabel; //"next"; 
}



