var xoff,yoff,// (xoff,yoff) = drag offset
    wid,hei,// attempt at width,height of whole window (hard to calculate in IE)
    tilex,tiley,// size of tiles
    img,// image data
    deb=0,// debug flag
    disp,// (w,h)=size of display, (x,y)=position in extended image of top-left displayed corner
    div0,div1obj,div2obj,div3obj,
    lrs,// long range scan
    hist,last,
    auximg,imgpri,imgcache,nloaded,maximgq,numimgq,preempt,maxgifcachescale,
    imgloc,
    comdir;// common directory
function min(x,y){if(x<y)return x; else return y;}
function max(x,y){if(x>y)return x; else return y;}
function maxu(x,y){if(y!=undefined&&y>x)return y; else return x;}
function esc(x){return x.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\n/g,"<br>");}
function pr(x){if(deb)document.getElementById("l4").innerHTML=x}
function prlast(x){
  var i,s
  last.a[last.p]=x;last.p=(last.p+1)%last.m;last.n++
  if(last.n>=last.m)i=last.p; else i=0
  s=''
  while(1){
    s+=last.a[i]+'<br>\n'
    i=(i+1)%last.m
    if(i==last.p)break
  }
  pr(s)
}
function setopacity(x,o){
  x.style.opacity=o+''
  if(x.style.filter!=undefined)x.style.filter='alpha(opacity='+o*100+')'
  if(x.style.MozOpacity!=undefined)x.style.MozOpacity=o+''; // necessary?
}
function movemain(e){
  if(!e)e=window.event
  var x,y,x0,y0,x1,y1,x2,y2,maxx,maxy
  x0=xoff-e.clientX;y0=yoff-e.clientY;// new position in extended image of top-left displayed corner
  if(deb)document.getElementById("l1").innerHTML="movemain "+e.clientX+" "+e.clientY
  if(x0<disp.minx){xoff-=x0-disp.minx;x0=disp.minx;}
  if(y0<disp.miny){yoff-=y0-disp.miny;y0=disp.miny;}
  if(x0>disp.maxx){xoff-=x0-disp.maxx;x0=disp.maxx;}
  if(y0>disp.maxy){yoff-=y0-disp.maxy;y0=disp.maxy;}
  newdisppos(x0,y0,0)
  return false
}
function movelrs(e){
  if(!e)e=window.event
  setlrs(xoff+e.clientX,yoff+e.clientY)
  return false
}
function setlrs(x,y){
  var x0,y0
  x0=Math.floor(lrs.scx*(x+.5))
  y0=Math.floor(lrs.scy*(y+.5))
  if(deb)document.getElementById("l1").innerHTML="setlrs "+x+' '+y
  newdisppos(x0,y0,0)
}
function jumplrs(e){// Set to catch click events in enclosing div of lrs image
  //                   - works if click occurs in white rectangle
  if(!e)e=window.event
  if(e.clientX!=lrs.dx||e.clientY!=lrs.dy)return false;
  //hist+='jumplrs '+e.clientX+' '+e.clientY+'    '+lrs.dx+' '+lrs.dy+'&nbsp;|';pr(hist)
  setlrs(e.clientX-disp.w-div0.l+lrs.w-disp.w/2/lrs.scx,e.clientY-disp.h-div0.t+lrs.h-disp.h/2/lrs.scy)
  return false
}
function jumplrsi(e){// Set to catch click events in the lrs image,
  //                    but won't work if click occurs in white rectangle
  if(!e)e=window.event
  //hist+='jumplrsi '+e.clientX+' '+e.clientY+'&nbsp;|';pr(hist)
  setlrs(e.clientX-disp.w-div0.l+lrs.w-disp.w/2/lrs.scx,e.clientY-disp.h-div0.t+lrs.h-disp.h/2/lrs.scy)
  return false
}
function downmain(e){
  if(!e)e=window.event
  if(deb)document.getElementById("l0").innerHTML="downmain"
  xoff=disp.x+e.clientX
  yoff=disp.y+e.clientY
  document.onmousemove=movemain
  return false
}
function dblclickmain(e){
  var x,y
  if(!e)e=window.event
  x=(disp.x+e.clientX)/img.w
  y=(disp.y+e.clientY)/img.h
  if(ctrl.m<ctrl.m1){
    document.getElementById('ctrl'+ctrl.m).src=ctrlimage(ctrl.m)+'.0.gif'
    ctrl.m++;
    document.getElementById('ctrl'+ctrl.m).src=ctrlimage(ctrl.m)+'.1.gif'
    initderivedparameters()
  }
  newdisppos(x*img.w-disp.w/2,y*img.h-disp.h/2,1)
  return false
}
function downlrs(e){
  if(!e)e=window.event
  if(deb)document.getElementById("l0").innerHTML="downlrs"
  xoff=Math.floor(disp.x/lrs.scx)-e.clientX
  yoff=Math.floor(disp.y/lrs.scy)-e.clientY
  lrs.dx=e.clientX;lrs.dy=e.clientY
  document.onmousemove=movelrs
  return false
}
function up(e){
  if(!e)e=window.event
  document.onmousemove=null
  if(deb)document.getElementById("l0").innerHTML="up"
}
function over(e){
  if(!e)e=window.event
  if(deb)pr('over '+e.clientX+' '+e.clientY)
}
function out(e){
  if(!e)e=window.event
  if(deb)document.getElementById("l2").innerHTML="out "+e.clientX+" "+e.clientY
  if(e.clientX<0||e.clientX>=wid||e.clientY<0||e.clientY>=hei)up(e)
}
function getwinsize(){
/*
  pr('X '+window.width+' '+window.height+' / '+
     'A '+window.innerWidth+' '+window.innerHeight+' / '+
     'B '+document.documentElement.clientWidth+' '+document.documentElement.clientHeight+' / '+
     'C '+document.body.clientWidth+' '+document.body.clientHeight+' / '+
     'F '+parseInt(div0.o.style.width)+' '+parseInt(div0.o.style.height)+' / '+
     'G '+document.body.scrollWidth+' '+document.body.scrollHeight+'\n')
*/
  wid=0;hei=0
  wid=maxu(wid,window.innerWidth)//A
  hei=maxu(hei,window.innerHeight)
  var d=document.documentElement
  if(d&&wid==0&&hei==0){
    wid=maxu(wid,d.clientWidth)//B
    hei=maxu(hei,d.clientHeight)
  }
  if(wid==0&&hei==0){
    d=document.body
    if(d){
      wid=maxu(wid,d.clientWidth)//C
      hei=maxu(hei,d.clientHeight)
    }else{
      wid=parseInt(div0.o.style.width);hei=parseInt(div0.o.style.height)//F
    }
  }
  if(deb)hei-=300
  showsize()
}
function showsize(){if(deb)document.getElementById("l3").innerHTML=wid+' '+hei+'<br>\n';}
function resize(){
  var x,y
  x=disp.x+disp.w/2
  y=disp.y+disp.h/2
  getwinsize()
  initderivedparameters()
  newdisppos(x-disp.w/2,y-disp.h/2,1)
  return false
}
function changeimgpri(s,p){
  //hist+=s+' '+p+'<br>'
  //pr(hist)
  var f
  //prlast('try '+s+' '+p)
  if(imgpri[2].l[s]!=undefined)f=2; else if(p==0&&imgpri[1].l[s]!=undefined)f=1; else return;
  delete imgpri[f].l[s];imgpri[f].n--
  imgpri[p].l[s]=1;imgpri[p].n++
  //prlast('done '+s+' '+p)
}
function imgloaded(){
  if(numimgq==0)alert('numimgq=0'); else numimgq--;
  nloaded++
  addtoimgqueue()
  //pr(imgpri[0].n+' '+imgpri[1].n+' '+imgpri[2].n+', loading '+numimgq+', loaded '+nloaded)
}
function addtoimgqueue(){
  //return
  var i,x
  for(i=0;i<3;i++){
    for(x in imgpri[i].l){
      if(numimgq==maximgq)return
      if(imgcache[x]!=undefined)alert('redefining '+x)
      numimgq++
      imgcache[x]=new Image()
      imgcache[x].src=x
      imgcache[x].onload=imgloaded
      delete imgpri[i].l[x];imgpri[i].n--
      //dump('queued '+x+' pending '+numimgq+'\n')
    }
  }
}
function newdisppos(x0,y0,ref){
  var c,r,t,x,y,im,i0,j0,i1,j1,x1,y1,x2,y2
  disp.x=x0=min(max(Math.floor(x0+.5),disp.minx),disp.maxx)
  disp.y=y0=min(max(Math.floor(y0+.5),disp.miny),disp.maxy)
  x=(x0+1000*tilex)%tilex;i0=(x0-x)/tilex;i1=min(Math.floor((x0+disp.w-1)/tilex),img.nx-1)
  y=(y0+1000*tiley)%tiley;j0=(y0-y)/tiley;j1=min(Math.floor((y0+disp.h-1)/tiley),img.ny-1)
  if(ref==0&&i0==disp.i0&&j0==disp.j0&&i1==disp.i1&&j1==disp.j1){
    div3obj.style.left=-x+'px'
    div3obj.style.top=-y+'px'
  }else{
    t='\n<div id="div3id" style="width:'+(disp.w+x)+'px;height:'+(disp.h+y)+'px;'
    t+='position:absolute;left:'+(-x)+'px;top:'+(-y)+'px;background-color:#000000">\n'
    for(r=max(j0,0);r<=j1;r++)for(c=max(i0,0);c<=i1;c++){
      t+='<div style="position:absolute;width:'+tilex+'px;height:'+tiley+'px;'
      t+='left:'+(c-i0)*tilex+'px;top:'+(r-j0)*tiley+'px">\n'
      t+='<img src='+imgloc+'x'+c+'.y'+r+'.jpg width="'+tilex+'px" height="'+tiley+'px" alt="Ix'+c+'y'+r+'">'
      t+='</div>\n'
      if(ctrl.ov){
        t+='<div style="position:absolute;width:'+tilex+'px;height:'+tiley+'px;left:'+(c-i0)*tilex+'px;top:'+(r-j0)*tiley+'px">\n'
        t+='<img src='+imgloc+'x'+c+'.y'+r+'.s'
        if(ctrl.m>=0)t+='+'+ctrl.m; else t+='-'+(-ctrl.m)
        t+='.gif width="'+tilex+'px" height="'+tiley+'px" alt="Ox'+c+'y'+r+'">'
        t+='</div>\n'
      }
    }
    t+='</div><!-- close div3id -->\n'
    div2obj.innerHTML=t
    div3obj=document.getElementById("div3id")
    div3obj.onmousedown=downmain
    div3obj.ondblclick=dblclickmain
    disp.i0=i0;disp.j0=j0;disp.i1=i1;disp.j1=j1
    //pr(esc(t))
    var i2,j2,i3,j3,pri
    x=(x0-preempt+1000*tilex)%tilex;i2=(x0-preempt-x)/tilex;i3=min(Math.floor((x0+preempt+disp.w-1)/tilex),img.nx-1)
    y=(y0-preempt+1000*tiley)%tiley;j2=(y0-preempt-t)/tiley;j3=min(Math.floor((y0+preempt+disp.h-1)/tiley),img.ny-1)
    if(ctrl.m>=0)t='+'+ctrl.m; else t='-'+(-ctrl.m)
    for(r=max(j2,0);r<=j3;r++)for(c=max(i2,0);c<=i3;c++){
      pri=(c>=i0&&c<=i1&&r>=j0&&r<=j1?0:1)
      changeimgpri(imgloc+'x'+c+'.y'+r+'.jpg',pri)
      if(ctrl.ov)changeimgpri(imgloc+'x'+c+'.y'+r+'.s'+t+'.gif',pri)
    }
    addtoimgqueue()
  }
  lrs.go.style.left=Math.floor((x0+disp.w/2)/lrs.scx)+'px'
  lrs.go.style.top=Math.floor((y0+disp.h/2)/lrs.scy)+'px'
  //pr(esc(div1obj.innerHTML))
  //pr(lrs.go.style.left+' '+lrs.go.style.top)
  //pr('x,y = '+x+' '+y+' / '+x0+' '+y0)
  //pr(imgpri[0].n+' '+imgpri[1].n+' '+imgpri[2].n+', loading '+numimgq+', loaded '+nloaded)
  //pr(esc(div0.o.innerHTML))
  //pr(div0.o.style.width+' '+div0.o.style.height);
}
function ctrlimage(m){
  var t
  if(m<ctrl.m0)t='ovl'; else if(m==ctrl.m0)t='botmag'; else
    if(m==ctrl.m1)t='topmag'; else t='midmag'
  return comdir+t
}
function initctrl(){
  var m,t,y
  ctrl.o.style.width=ctrl.w+'px'
  t=''
  for(m=ctrl.m0-1;m<=ctrl.m1;m++){
    y=m+4-ctrl.m0;if(m<ctrl.m0)y-=1
    y=-y*(ctrl.h+ctrl.s)-10;
    if(m==ctrl.m1)y-=ctrl.h0
    t+='<div style="position:absolute;left:0px;top:'+y+'px;z-index:1">'
    t+='<img id="ctrl'+m+'" onclick="ctrlclick('+m+')" src="'+ctrlimage(m)+'.'
    if(m==ctrl.m||(m<ctrl.m0&&ctrl.ov))t+='1'; else t+='0'
    t+='.gif"></div>\n'
  }
  ctrl.o.innerHTML=t
  //pr(esc(t))
}
function init0(){// First-time initialisation (executed once per page load)
  var i,j,m,t
  if(deb){
    document.write('<div id="l0">(down/up)<br></div>\n')
    document.write('<div id="l1">(move)<br></div>\n')
    document.write('<div id="l2">(out)<br></div>\n')
    document.write('<div id="l3">(size)<br></div>\n')
    document.write('<div id="l4">(misc)<br></div>\n')
  }
  if(imgloc==undefined)imgloc=''
  if(ctrl.m0<0&&((img.tx|img.ty)&((1<<(-ctrl.m0))-1)))alert('Error: min scaled tile size non-integral')
  
  comdir='../../common/'
  div0.o=document.getElementById("div0id")
  div1obj=document.getElementById("div1id")
  div2obj=document.getElementById("div2id")
  lrs.o=document.getElementById("lrsid")
  lrs.io=document.getElementById("lrsiid")
  lrs.go=document.getElementById("lrsgrabid")
  lrs.bo=document.getElementById("lrsbigid")
  lrs.so=document.getElementById("lrssmallid")
  ctrl.o=document.getElementById("ctrlid")

  auximg=new Array(10)
  for(i=0;i<4;i++)for(j=0;j<2;j++){
    auximg[i*2+j]=new Image()
    auximg[i*2+j].src=comdir+['ovl','botmag','midmag','topmag'][i]+'.'+j+'.gif'
  }
  for(i=0;i<2;i++){
    auximg[8+i]=new Image()
    auximg[8+i].src=imgloc+'lrs.'+i+'.jpg'
  }
  imgpri=new Array(3)
  for(i=0;i<3;i++)imgpri[i]={n:0,l:{}}
  imgcache={}
  img.nx=Math.floor((img.w0+img.tx-1)/img.tx)
  img.ny=Math.floor((img.h0+img.ty-1)/img.ty)
  for(i=0;i<img.nx;i++){
    for(j=0;j<img.ny;j++){
      imgpri[2].l[imgloc+'x'+i+'.y'+j+'.jpg']=1
      imgpri[2].n++
    }
  }
  for(m=ctrl.m0;m<=min(ctrl.m1,maxgifcachescale);m++){
    if(m>=0)t='+'+m; else t='-'+(-m)
    for(i=0;i<img.nx;i++)for(j=0;j<img.ny;j++){
      imgpri[2].l[imgloc+'x'+i+'.y'+j+'.s'+t+'.gif']=1
      imgpri[2].n++;
    }
  }
  nloaded=0;numimgq=0
  hist='';last={m:10,n:0,p:0,a:[]}

  getwinsize()
  initderivedparameters()
  setopacity(lrs.bo,.4)
  setopacity(lrs.so,.4)

  // Set handlers last (newdisppos and initctrl also set handlers)
  newdisppos((img.w-disp.w)/2,(img.h-disp.h)/2,1)
  initctrl()
  window.onresize=resize
  document.onmouseup=up
  document.onmouseover=over
  //document.onmouseout=out
  div1obj.onmouseout=out
  lrs.o.onclick=jumplrs
  lrs.io.onclick=jumplrsi
  lrs.go.onmousedown=downlrs
  //setTimeout(resize,100)
}
function initderivedparameters(){// Called at start, every resize, change of scale, change of overlay flag
  var i,j,m,t
  m=ctrl.m
  if(m>=0){tilex=img.tx<<m;tiley=img.ty<<m;img.w=img.w0<<m;img.h=img.h0<<m;} else
          {tilex=img.tx>>(-m);tiley=img.ty>>(-m);img.w=img.w0>>(-m);img.h=img.h0>>(-m);}
  disp={}
  //pr(''+div0.r)
  disp.w=wid-div0.l-div0.r;disp.h=hei// slightly more efficient if these are one more than multiple of tilex,tiley
  disp.i0=disp.j0=disp.i1=disp.j1=-1000000
  img.r=max(lrs.w+lrs.l,ctrl.w)
  disp.maxx=img.w+img.r-disp.w;if(disp.maxx>=0)disp.minx=0; else disp.minx=disp.maxx=Math.floor(disp.maxx/2)
  disp.maxy=img.h-      disp.h;if(disp.maxy>=0)disp.miny=0; else disp.miny=disp.maxy=Math.floor(disp.maxy/2)
  lrs.scx=img.w/lrs.w;lrs.scy=img.h/lrs.h
  lrs.scx=img.w/lrs.w;lrs.scy=img.h/lrs.h
  lrs.sw=Math.floor(disp.w/2/lrs.scx)
  lrs.sh=Math.floor(disp.h/2/lrs.scy)
  lrs.gr=max(min(12,20-min(lrs.sw,lrs.sh)),0)
  lrs.bw=lrs.sw+lrs.gr
  lrs.bh=lrs.sh+lrs.gr
  div0.o.style.width=disp.w+div0.l+'px';div0.o.style.height=disp.h+div0.t+div0.b+'px'
  div1obj.style.width=disp.w+'px';div1obj.style.height=disp.h+'px'
  div1obj.style.left=div0.l+'px';div1obj.style.top=div0.t+'px'
  div2obj.style.width=disp.w+'px';div2obj.style.height=disp.h+'px'
  lrs.o.style.width=lrs.w+'px';lrs.o.style.height=lrs.h+'px'
  lrs.o.style.left=disp.w-lrs.w-lrs.l+'px';lrs.o.style.top=disp.h-lrs.h-lrs.t+'px'
  lrs.io.style.width=lrs.w+'px';lrs.io.style.height=lrs.h+'px'
  lrs.io.src=imgloc+'lrs.'+ctrl.ov+'.jpg'
  lrs.so.style.left=-lrs.sw-1+'px'
  lrs.so.style.top=-lrs.sh-1+'px'
  lrs.so.style.width=lrs.sw*2+1+'px'
  lrs.so.style.height=lrs.sh*2+1+'px'
  lrs.bo.style.left=-lrs.bw+'px'
  lrs.bo.style.top=-lrs.bh+'px'
  lrs.bo.style.width=lrs.bw*2+1+'px'
  lrs.bo.style.height=lrs.bh*2+1+'px'
  //pr(esc(div1obj.innerHTML))
  lrs.dx=lrs.dy=-1000000;// last mouse-down position in the grab object
  ctrl.o.style.left=disp.w-ctrl.w+'px'
  ctrl.o.style.top=disp.h-lrs.h+'px'
}
function ctrlclick(m){
  var o,x,y
  o=document.getElementById('ctrl'+m)
  if(m<ctrl.m0){// toggle overlay
    ctrl.ov=1-ctrl.ov
    o.src=comdir+'ovl.'+ctrl.ov+'.gif'
    lrs.io.src=imgloc+'lrs.'+ctrl.ov+'.jpg'
  }else{// set new scale
    document.getElementById('ctrl'+ctrl.m).src=ctrlimage(ctrl.m)+'.0.gif'
    ctrl.m=m
    o.src=ctrlimage(m)+'.1.gif'
    x=(disp.x+disp.w/2)/img.w
    y=(disp.y+disp.h/2)/img.h
    initderivedparameters()
    disp.x=x*img.w-disp.w/2
    disp.y=y*img.h-disp.h/2
  }
  newdisppos(disp.x,disp.y,1)
  //pr('ctrlclick '+m)
  //pr(esc(lrs.o.innerHTML))
  return false
}

