/*
 * archive.js - viewer for newspaper archives
 * 
 * Copyright (C) 2005  Toni Ronkko
 * 
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * ``Software''), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 * 
 *
 * Dec 15 2005, Toni Ronkko <tr atsign eppunormaali dot net>
 *
 */

/* index of current page */
var ar_curpage = 0;

/* number of elements in a row */
var ar_elems = 4;

/* number of pages */
var ar_npages;

/* array of pages */
var ar_pages;

/* pre-loaded images */
var ar_images = new Array;

/* drag operation in effect? */
var ar_dragging = false;

/* latest cursor position while dragging */
var ar_drag_x = 0;
var ar_drag_y = 0;

/* scrolling speed due to drag operation */
var ar_drag_speed = 4;

/* time of last drag */
var ar_last_drag = null;


/*
 * Initialize news archive and print user interface elements to current 
 * position in HTML page.
 */
function archive(p) {
  /* store pages */
  ar_pages = p;

  /* compute number of pages */
  ar_npages = Math.floor((ar_pages.length + ar_elems - 1) / ar_elems);

  /* toolbar */
  document.write("<div class=\"ar_bar\">");

  /* previous page */
  document.write("<input type=\"button\" class=\"ar_button\" name=\"ar_prev\" id=\"ar_prev\" value=\"&lt;&lt;\" onclick=\"javascript:ar_prev();\" title=\"Edellinen sivu\"/>&nbsp;&nbsp;&nbsp;");

  /* current page number */
  document.write("<input type=\"edit\" name=\"ar_page\" id=\"ar_page\" disabled size=\"9\" class=\"ar_page\"></input>");

  /* next page */
  document.write("<input type=\"button\" class=\"ar_button\" name=\"ar_next\" id=\"ar_next\" value=\"&gt;&gt;\" onclick=\"javascript:ar_next();\" title=\"Seuraava sivu\"/>&nbsp;&nbsp;&nbsp;&nbsp;");

  /* zoom */
  document.write("<font class=\"ar_zoom\">Näytä:</font>&nbsp;");
  document.write("<select class=\"ar_view\" title=\"Sovita sivu ruudulle\" name=\"ar_zoom\" id=\"ar_zoom\" onchange=\"javascript:ar_refresh()\">");
  document.write("<option default>Koko sivu</option>");
  document.write("<option>Sivun leveys</option>");
  document.write("<option> 50%</option>");
  document.write("<option> 75%</option>");
  document.write("<option>100%</option>");
  document.write("<option>125%</option>");
  document.write("<option>150%</option>");
  document.write("<option>200%</option>");
  document.write("</select>&nbsp;&nbsp;");

  /* help */
  document.write("<input type=\"button\" class=\"ar_button\" name=\"ar_help\" id=\"ar_help\" value=\"Ohje\" onclick=\"javascript:ar_help();\" title=\"Ohjeita tämän lukuohjelman käyttöön\" />&nbsp;&nbsp;");

  /* close */
  document.write("<input type=\"submit\" class=\"ar_button\" value=\"Sulje\" onclick=\"javascript:ar_close();return(false);\" title=\"Sulje artikkeliselain ja palaa edelliselle sivulle.\">");

  document.write("</div>");

  /* canvas */
  document.write("<div class=\"ar_canvas\"><img onmouseout=\"return ar_end_drag(event);\" ondblclick=\"return ar_cycle();\" onmousedown=\"return ar_init_drag(event);\" onmouseup=\"return ar_end_drag(event);\" class=\"ar_image\" name=\"ar_image\" id=\"ar_image\" onmousemove=\"return ar_drag(event);\" /></div>");

  /* install keyboard handler */
  if(document.addEventListener){
    /* mozilla */
    document.addEventListener("keypress", ar_key, true); 
  } else {
    /* MSIE */
    document.attachEvent("onkeypress", ar_key);
  }

  /* load first page */
  ar_curpage = 0;
  ar_refresh();
}

/* 
 * Refresh screen by re-loading the page kept in by ar_curpage variable.
 */
function ar_refresh() {
  /* retrieve pointer to selection list component */
  var f = document.getElementById("ar_zoom");

  /* convert list index to zoom ratio */
  var zoom = 0;
  switch (f.selectedIndex) {
  case 2:
    zoom = 0.5;
    break;

  case 3:
    zoom = 0.75;
    break;

  case 4:
    zoom = 1.0;
    break;

  case 5:
    zoom = 1.25;
    break;

  case 6:
    zoom = 1.5;
    break;

  case 7:
    zoom = 2.0;
    break;

  case 0:
  case 1:
  default:
    /* get width and height of browser window */
    var width  = ar_winwidth();
    var height = ar_winheight();

    /* compute zoom factor */
    if (f.selectedIndex == 0) {
      /* whole page */
      zoom = height / (ar_pages[ar_curpage*ar_elems+2] + 120);
      if ((ar_pages[ar_curpage*ar_elems+1] + 40) * zoom > width) {
        /* window too slim to show full page */
        zoom = width / (ar_pages[ar_curpage*ar_elems+1] + 40);
      }
    } else {
      /* fit width */
      zoom = width / (ar_pages[ar_curpage*ar_elems+1] + 40);
    }

    /* refuse to enlarge image/shrink too much */
    if (zoom > 1) {
      zoom = 1;
    }
    if (zoom < 0.2) {
      zoom = 0.2;
    }
  }

  /* find image component */
  var img = document.getElementById("ar_image");

  /* load page image (usually from cache) */
  if (ar_images[ar_curpage] == null) {
    ar_images[ar_curpage] = new Image();
    ar_images[ar_curpage].src = ar_pages[ar_curpage*ar_elems];
  }
  img.src    = ar_images[ar_curpage].src
  img.width  = Math.floor(ar_pages[ar_curpage*ar_elems+1] * zoom);
  img.height = Math.floor(ar_pages[ar_curpage*ar_elems+2] * zoom);

  /* show page number on screen */
  var f = document.getElementById("ar_page");
  f.value = "Sivu: " + (ar_curpage + 1) + "/" + ar_npages;

  /* 
   * Enable/disable prev and next buttons.  Doing gives user a visual clue
   * that there are no more pages.  However, disabling a component that has
   * focus also prevents further key strokes from being registered.
   * Thus, focus must be moved to an enabled component.
   */
  var prev = document.getElementById("ar_prev");
  var next = document.getElementById("ar_next");
  if (ar_curpage == 0) {
    next.disabled = false;
    next.focus();
    prev.disabled = true;
  } else { 
    prev.disabled = false;
  } 
  if (ar_curpage == ar_npages - 1) {
    prev.focus();
    next.disabled = true;
  } else { 
    next.disabled = false;
  }

  /* pre-load next page */
  if (ar_curpage+1 < ar_npages) {
    if (ar_images[ar_curpage+1] == null) {
      ar_images[ar_curpage+1] = new Image();
      ar_images[ar_curpage+1].src = ar_pages[(ar_curpage+1)*ar_elems];
    }
  }
}


/*
 * Load ith page to screen.
 */
function ar_load(i) {
  if (0 <= i  &&  i < ar_npages) {
    /* save page number */
    ar_curpage = i;
    ar_refresh();
  }
}


/*
 * Load previous page.
 */
function ar_prev() {
  if (ar_curpage > 0) {
    ar_load(ar_curpage - 1);
    window.scrollTo(999999,999999);
  }
}


/*
 * Load next page.
 */
function ar_next() {
  if (ar_curpage < ar_npages - 1) {
    window.scrollTo(0,0);
    ar_load(ar_curpage + 1);
  }
}


/*
 * Start a drag operation when user presses left mouse button down over
 * canvas.
 */
function ar_init_drag(e) {
  /* for MSIE */
  if (!e) { e = window.event; }

  /* set up dragging */
  ar_dragging = true;
  ar_drag_x = e.screenX;
  ar_drag_y = e.screenY;
  ar_last_drag = (new Date()).getTime();

  /* change cursor to indicate drag */
  var f = document.getElementById("ar_image");
  if (f) {
    f.style.cursor = "move";
  }

  /* return false to tell the browser not to initiate its own drag */
  return false;
}


/*
 * End dragging operation after user releases the left mouse button.
 *
 * BUGS: This function is not called in Opera 9 or Mozilla 1.7, if user
 * moves the mouse cursor outside the browser window before releasing
 * the button.  This in turn causes the dragging operation to continue
 * until the user clicks a mouse button.  The problem could be fixed
 * by ending the drag operation whenever the mouse cursor leaves the image
 * (that is, add onmouseout=\"return ar_end_drag(event);\" to image tag).
 * However, this causes a dragging operation to end prematurely if user
 * accidentally moves mouse cursor outside the image, and therefore does
 * not completety fix the problem.
 */
function ar_end_drag(e) {
  /* for MSIE */
  if (!e) { e = window.event; }

  ar_dragging = false;

  /* change cursor shape to indicate end of drag */
  var f = document.getElementById("ar_image");
  if (f) {
    f.style.cursor = "auto";
  }

  /* do not initiate an action */
  return false;
}



/*
 * Cycle between zoom modes.
 *
 * BUGS: This very function is set to be triggered when the user double
 * clicks on the image.  However, in Mozilla 1.7, the function is not called
 * with every double click.  It seems that the event is missed if the multiple
 * double clicks are come in quick fashion.
 */
function ar_cycle() {
  /* retrieve pointer to selection list component */
  var f = document.getElementById("ar_zoom");

  /* change selection index */
  switch (f.selectedIndex) {
  case 0:
    /* whole page -> fit width */
    f.selectedIndex = 1;
    break;

  case 1:
    /* fit width -> 100% */
    f.selectedIndex = 4;
    break;

  case 2:
    /* 50% -> 100% */
    f.selectedIndex = 4;
    break;

  case 3:
    /* 75% -> 100% */
    f.selectedIndex = 4;
    break;

  case 4:
    /* 100% -> 150% */
    f.selectedIndex = 6;
    break;

  case 5:
    /* 125% -> whole page */
    f.selectedIndex = 0;
    break;

  case 6:
    /* 150% -> whole page */
    f.selectedIndex = 0;
    break;

  case 7:
    /* 200% -> whole page */
    f.selectedIndex = 0;
    break;
  }

  /* change zoom */
  ar_refresh();
  return false;
}



/*
 * Update page position when dragging page with mouse.
 */
function ar_drag(e) {
  /* for MSIE */
  if (!e) { e = window.event; }

  /* get current time */
  var now = (new Date()).getTime();

  if (ar_dragging  &&  now > ar_last_drag + 100) {
    /* compute offset since last event */
    var x = (ar_drag_x - e.screenX) * ar_drag_speed;
    var y = (ar_drag_y - e.screenY) * ar_drag_speed;

    /* scroll window */
    if (x != 0  ||  y != 0) {
      window.scrollBy(x,y);
    }

    /* store current pos and time */
    ar_drag_x = e.screenX;
    ar_drag_y = e.screenY;
    ar_last_drag = now;
  }

  return false;
}


/*
 * Handle key presses.
 */
function ar_key(e) {
  /* for MSIE */
  if (!e) { e = window.event; }

  /* get the key code */
  var key = null;
  if (e.which) {
    key = String.fromCharCode(e.which);
  } else if (e.keyCode) {
    key = String.fromCharCode(e.keyCode);
  }

  if (key == '+') {
    /* retrieve pointer to selection list component */
    var f = document.getElementById("ar_zoom");

    /* change selection index */
    switch (f.selectedIndex) {
    case 0:
      /* whole page -> fit width */
      f.selectedIndex = 1;
      break;

    case 1:
      /* fit width -> 100% */
      f.selectedIndex = 4;
      break;

    case 2:
      /* 50% -> 75% */
      f.selectedIndex = 3;
      break;

    case 3:
      /* 75% -> 100% */
      f.selectedIndex = 4;
      break;

    case 4:
      /* 100% -> 125% */
      f.selectedIndex = 5;
      break;

    case 5:
      /* 125% -> 150% */
      f.selectedIndex = 6;
      break;

    case 6:
      /* 150% -> 200% */
      f.selectedIndex = 7;
      break;

    case 7:
      /* stay at 200% */
      break;
    }

    /* change zoom */
    ar_refresh();
    return false;
  } else if (key == '-') {
    /* retrieve pointer to selection list component */
    var f = document.getElementById("ar_zoom");

    /* change selection index */
    switch (f.selectedIndex) {
    case 0:
      /* stay at whole page  */
      f.selectedIndex = 1;
      break;

    case 1:
      /* fit width -> whole page */
      f.selectedIndex = 0;
      break;

    case 2:
      /* stay at 50% */
      break;

    case 3:
      /* 75% -> 50% */
      f.selectedIndex = 2;
      break;

    case 4:
      /* 100% -> 75% */
      f.selectedIndex = 3;
      break;

    case 5:
      /* 125% -> 100% */
      f.selectedIndex = 4;
      break;

    case 6:
      /* 150% -> 125% */
      f.selectedIndex = 5;
      break;

    case 7:
      /* 200% -> 150% */
      f.selectedIndex = 6;
      break;
    }

    /* change zoom */
    ar_refresh();
    return false;
  } else if (key == '0') {
    /* reset zoom */
    var f = document.getElementById("ar_zoom");
    f.selectedIndex = 4;
    ar_refresh();
    return false;
  } else if (key == "<") {
    ar_prev();
    return false;
  } else if (key == ">") {
    ar_next();
    return false;
  } else {
    return true;
  }
}


/*
 * Close the article reader by loading another html document.  If the
 * referrer is a page at http://eppunormaali.net/juttuarkisto, then 
 * return directly to the refering page.  Otherwise, return to main page.
 */
function ar_close() {
  /* extract base url of this document */
  var thisbase = ar_base(document.URL);

  /* extract base url of referring document */
  var refbase = ar_base(document.referrer);
  
  /* conditionally jump to referring document */
  if (thisbase.toLowerCase() == refbase.toLowerCase()) {
    /* referrer resides in the very same directory */
    history.go(-1);
  } else {
    /* referrer from another directory/site */
    location.href = "index.php";
  }
}


/*
 * Given an url address, strip out the file name.  That is, given url
 * "http://eppunormaali.net/juttuarkisto/index.html", return the url
 * "http://eppunormaali.net/juttuarkisto/"
 */
function ar_base(url) {
  var pos = document.URL.lastIndexOf("/");
  if (pos >= 0) {
    return url.substr(0,pos);
  } else {
    /* no slash in url? */
    return url;
  }
}


/*
 * Open help window.
 */
function ar_help() {
  window.location = "help.php#start";
  return false;
}


/* 
 * Get width of browser window.  For more info on this,
 * please see http://www.quirksmode.org/js/doctypes.html and
 * http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
 */
function ar_winwidth() {
  var w = 0;
  if (window.innerWidth) {
    /* Opera, Mozilla, Safari, Netscape */
    w = window.innerWidth;
  } else if (document.documentElement.clientWidth) {
    /* MSIE 6+ Strict */
    w = document.documentElement.clientWidth;
  } else if (document.body.clientWidth) {
    /* MSIE 5+ Quirks */
    h = document.body.clientWidth;
  }

  /* fallback */
  if (w < 600) {
    w = 600;
  }
  return w;
}


/*
 * Get height of browser window.
 */
var clicks = 0;
function ar_winheight() {
  var h;
  if (window.innerHeight) {
    /* Opera, Mozilla, Safari, Netscape */
    h = window.innerHeight;
  } else if (document.documentElement.clientHeight) {
    /* MSIE 6+ Strict */
    h = document.documentElement.clientHeight;
  } else if (document.body.clientHeight) {
    /* MSIE 5+ Quirks */
    h = document.body.clientHeight;
  }

  /* fallback */
  if (h < 450) {
    h = 450;
  }
  return h;
}
