function dw()
{
    for(var i=0;i<arguments.length;++i) 
    {
	document.write(arguments[i]);
    }
}

function getelem(id)
{
    return document.getElementById(id);
}
    
function make_and_run_animator(theid,data,varnm)
{
    var animator = new createAnimator(theid,data,varnm);
    animator._init(0);
    animator.run();
    return animator;
}


function createAnimator(theid,data,varnm)
{
    //this.sequence = ['ident','string','int','char','comment','space','newline'];

    this.id = theid;
    this.varnm  = varnm;

    this.alldata = data;

    this.clipidx = 0; //idx of current clip
    this.step_idx = 0; //index in this.alldata[step_idx] that was changed last
    this.mode_step_by_step = 0;

    this.state_of_choices = {}; //key is tokentype, value is choiceid

    this.timescale = 1/2;
    this.TOTALSTEP_DURATION = 1000;
    this.HIGHLIGHT_DURATION = 700;
    this.INTERCLIP_PAUSE = 6000;
    

    this._init = a_init;

    this.run = a_run;
    this._fill_first_frame = a__fill_first_frame;
    this.next_step  = a_next_step;
    this._unhighlight_and_setstr = a__unhighlight_and_setstr;
    this._sched_next_step =a__sched_next_step;

    this.pause_animation =  a_pause_animation;
    this.continue_animation =   a_continue_animation ;
    this.restart_from_1st_clip =  a_restart_from_1st_clip ;
    this.rewind_to_begining_of_cur_clip =  a_rewind_to_begining_of_cur_clip;
    this.rewind_to_begining_of_prev_clip =  a_rewind_to_begining_of_prev_clip;
    this.rewind_to_begining_of_next_clip =  a_rewind_to_begining_of_next_clip;
    this.attach_handlers_to_buttons  =  a_attach_handlers_to_buttons ;
    this.cmd_next_step = a_cmd_next_step;

    this.attach_handlers_to_options = a_attach_handlers_to_options;
    this._on_some_opt_changed = a__on_some_opt_changed;
    this._sched_next_step_explicit = a__sched_next_step_explicit;
    this._fill_first_frame_and_next_step = a__fill_first_frame_and_next_step;

    return this;
};

function a_run()
{
    this._sched_next_step(0);
}

function a_init(do_create_divs)
{
    if (do_create_divs) {
	    dw('<div id="' + this.id + '" class=animator-frame>');
	    dw('<div class=title-str>' +
		'<span id="' +this.id +'__title_str" class=title-str></span></div>');
	    dw('<div id="' + this.id + '__content" class=animator-frame-content>');
	    dw('</div></div>');
    };

    this.content_elem   = getelem(this.id + '__content'); 
	    //elem showing just clip itself i.e. no controls 
    this._fill_first_frame();
}

function htmlquote(s) { s= s.replace(' ','&nbsp;'); return s; }
function surhtmlquote(s) { return s; }

function a__fill_first_frame()
{
    this.content_elem.innerHTML = '';
    var data = this.alldata[this.clipidx].data;
    getelem(this.id + '__title_str').innerHTML = this.alldata[this.clipidx].title; 
    
    var html = '';
    for(var i=0;i<data.length;++i)
    {
	var ihtml = '<span><span id=' + this.id + 
	    '__content_item_' + i + ' class=' + data[i].type + '>' + 
		htmlquote(data[i]._orig) + 
	    ( data[i].type == 'punct' ?
		"<span zstyle='font-size:4px;' class=breakpt> </span>" : '') +
	    '</span></span>';
	html += ihtml;

    }
    html = 
	'<span id=' + this.id + '__pre_content class=precontent>' +
	    surhtmlquote(this.alldata[this.clipidx].data_surround[0][0]) + 
	    '</span>' +
	html +

	'<span id=' + this.id + '__post_content class=postcontent>' +
	    surhtmlquote(this.alldata[this.clipidx].data_surround[0][1]) + 
	    '</span>';
    this.content_elem.innerHTML = html;
}

function a__sched_next_step(is_long)
{
    this.timeoutType = 'next-step';
    this.timeoutID = setTimeout(this.varnm + '.next_step(0)',
	this.timescale*(this.TOTALSTEP_DURATION - 
	    (is_long ? 0 : this.HIGHLIGHT_DURATION))
	);
}

function a__sched_next_step_explicit(dur)
{
    this.timeoutType = 'next-step';
    this.timeoutID = setTimeout(this.varnm + '._fill_first_frame_and_next_step()',
	this.timescale*dur);
}


function a__fill_first_frame_and_next_step()
{
    this._fill_first_frame();  
    this.next_step(0)
}

function a_next_step(do_immediately)
{
    while (1) {
	var data = this.alldata[this.clipidx].data;    
	var surdata = this.alldata[this.clipidx].data_surround;
        if (data.length+surdata.length	 == this.step_idx)
	{
	    this.step_idx = 0;
	    if (++this.clipidx ==  this.alldata.length)
		this.clipidx = 0;
    	    if (do_immediately)
	    	this._fill_first_frame();
	    if (!do_immediately)
	    	this._sched_next_step_explicit(this.INTERCLIP_PAUSE);
	    return;
	} else if (data.length <= this.step_idx) {
	    //need to animate surround data
	    var sur_offs = this.step_idx - data.length;
	    getelem(this.id + '__pre_content').innerHTML = 	    
		surhtmlquote(surdata[sur_offs][0]);
	    getelem(this.id + '__post_content').innerHTML = 	    
		surhtmlquote(surdata[sur_offs][1]);
	    this.step_idx++;
	    if (!do_immediately)
	    	this._sched_next_step(1);
	    return;
	}
	/*not a corner case when we wrap. Just replace next token*/
        var tokinfo = data[this.step_idx];
	var tokelem = getelem(this.id + '__content_item_' + this.step_idx);
        var newstr = (this.state_of_choices[tokinfo.type] != undefined) ? 
	    tokinfo[this.state_of_choices[tokinfo.type]]
	    : (tokinfo._default == undefined ? tokinfo._orig : tokinfo._default);
        this.step_idx++;
	if (tokinfo._orig != newstr)
	{ 
	    if (this.tok_in_progress && this.tok_in_progress.elem && 
		this.tok_in_progress.elem.parentNode)
		this.tok_in_progress.elem.parentNode.className = '';
	    this.tok_in_progress = { elem: tokelem, str: newstr };
	    tokelem.parentNode.className = "animator-highlight";

	    if (do_immediately)
	    {
		this._unhighlight_and_setstr(do_immediately);
		return;
	    }
	    this.timeoutID = setTimeout(this.varnm + '._unhighlight_and_setstr(0)',
		this.timescale*this.HIGHLIGHT_DURATION);
	    this.timeoutType = 'unhighlight-and-setstr';
	
	    //tokelem.innerHTML = htmlquote(newstr);
	    return;
	}
    };
}


function a__unhighlight_and_setstr(do_immediately)
{
    this.tok_in_progress.elem.parentNode.className = 'animator-highlight-post';
    this.tok_in_progress.elem.innerHTML = htmlquote(this.tok_in_progress.str);    
    if (!this.mode_step_by_step && !do_immediately)
	this._sched_next_step(0);
}

/*here are functions that control animation*/
function a_pause_animation()
{
    this.mode_step_by_step = 1;
}

function a_continue_animation()
{
    this.mode_step_by_step = 0;
    this.next_step(0);
}

function a_restart_from_1st_clip()
{
    this.clipidx = 0;
    this.step_idx = 0;
    clearTimeout(this.timeoutID);
    this._fill_first_frame();
    this._sched_next_step(0);
}

function a_rewind_to_begining_of_cur_clip()
{
    this.step_idx = 0;
    clearTimeout(this.timeoutID);
    this._fill_first_frame();
    this._sched_next_step(0);
}

function a_rewind_to_begining_of_next_clip()
{
    if (++this.clipidx == this.alldata.length)
	this.clipidx = 0;
    this.step_idx = 0;
    clearTimeout(this.timeoutID);
    this._fill_first_frame();
    this._sched_next_step(0);
}

function a_rewind_to_begining_of_prev_clip()
{
    if (this.clipidx==0)
	this.clipidx = this.alldata.length-1;
    else
	--this.clipidx;
    this.step_idx = 0;
    clearTimeout(this.timeoutID);
    this._fill_first_frame();
    this._sched_next_step(0);
}


function a_cmd_next_step()
{
    //this.mode_step_by_step = 1;
    this.next_step(1);    
}


function a_attach_handlers_to_buttons(parentelem)
{
  var btns = parentelem.getElementsByTagName('img');
  for(var i=0;i<btns.length;++i) {
    var b = btns[i];
    var c = b.className;
    b['anim'] = this;
    if (c.indexOf('rewind_to_begining_of_next_clip')!=-1)
	b.onclick = function () { this.anim.rewind_to_begining_of_next_clip(); }
    if (c.indexOf('rewind_to_begining_of_cur_clip')!=-1)
	b.onclick = function () { this.anim.rewind_to_begining_of_cur_clip(); }
    if (c.indexOf('rewind_to_begining_of_prev_clip')!=-1)
	b.onclick = function () { this.anim.rewind_to_begining_of_prev_clip(); }
    if (c.indexOf('restart_from_1st_clip')!=-1)
	b.onclick = function () { this.anim.restart_from_1st_clip(); }
    if (c.indexOf('continue_animation')!=-1)
	b.onclick = function () { this.anim.continue_animation(); }
    if (c.indexOf('pause_animation')!=-1)
	b.onclick = function () { this.anim.pause_animation(); }    
    if (c.indexOf('next_step')!=-1)
	b.onclick = function () { this.anim.cmd_next_step(); }    
    if (c.indexOf('animation_slower')!=-1)
	b.onclick = function () { this.anim.timescale *= 2.0;; }    
    if (c.indexOf('animation_faster')!=-1)
	b.onclick = function () { this.anim.timescale /= 2.0;; }    

  };    
}



function a_attach_handlers_to_options(parentelem)
{
  for(var t=0;t<2;++t) {
    var elts = parentelem.getElementsByTagName(t ? 'select' : 'input');
    for(var i=0;i<elts.length;++i) {
	var e = elts[i];
	e.anim = this;
    };
  };    
}


function a__on_some_opt_changed()
{
    this.rewind_to_begining_of_cur_clip();
}

function opts_changed_checkbox(tokentype,elem,val_if_unchecked,val_if_checked)
{
    var anim = elem.anim;
    anim.state_of_choices[tokentype] = elem.checked ? 
	val_if_checked : val_if_unchecked;
    anim._on_some_opt_changed()
}

function opts_changed(tokentype,elem)
{
    var anim = elem.anim;
    anim.state_of_choices[tokentype] = elem.options[elem.selectedIndex].value;
    anim._on_some_opt_changed();
}

