//
// File: webcam.js
// Author: Steve Clarke
// Created: February 15th 2009
// Homepage:  http://www.trumpton.org.uk/webcamjs
//
// Provides and handles the <webcam> html tag
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// Acknowledgement to the original author should be made by embedding the following line of html
// into any page using this, or a derrivative of this javascript file:
//
// <p style="font-size: 40%">Webcam display source from <a href="http://www.trumpton.org.uk/webcamjs">trumpton</a></p>
//

 var count, errcount ;
 var CAP_JAVASCRIPT=0, CAP_MICROSOFT=1, CAP_CANVAS=2, CAP_CANVAS_MOZ=3, CAP_CANVAS_HTML5=4, capabilities=-1 ;

  // Work out what the browser capabilities are
  function getcapabilities()
  {
    if (capabilities<0) {
      var cnv = document.createElement("canvas");
      if (cnv.getContext) {
        var ctx=cnv.getContext("2d") ;
        if (ctx && ctx.fillText && ctx.getImageData) capabilities=CAP_CANVAS_HTML5 ;
        else if (ctx && ctx.mozDrawText) capabilities=CAP_CANVAS_MOZ ;
        else capabilities=CAP_CANVAS ;
      } else capabilities=CAP_MICROSOFT ;
    }
    return capabilities ;
  }

  // Copy Image Attributes
  function copyattributes(src, dst)
  {
    var srcimg=src.getAttribute("srcimg") ;
    var dstimg=dst.getAttribute("srcimg") ;
    if (!dstimg) dst.setAttribute("srcimg", srcimg) ;
    dst.width=src.width ;
    dst.height=src.height ;
    dst.setAttribute("webcam", src.getAttribute("webcam")) ;
    dst.setAttribute("height", src.getAttribute("height")) ;
    dst.setAttribute("width", src.getAttribute("width")) ;
    dst.setAttribute("id", src.getAttribute("id")) ;
    dst.setAttribute("name", src.getAttribute("name")) ;
    dst.setAttribute("alt", src.getAttribute("alt")) ;
    dst.setAttribute("showdate", src.getAttribute("showdate")) ;
    dst.setAttribute("flip", src.getAttribute("flip")) ;
    dst.setAttribute("rotate", src.getAttribute("rotate")) ;
    dst.setAttribute("refresh", src.getAttribute("refresh")) ;
    dst.setAttribute("graceful", src.getAttribute("graceful")) ;
    dst.setAttribute("bgc", src.getAttribute("bgc")) ;
    dst.setAttribute("fgc", src.getAttribute("fgc")) ;
    dst.setAttribute("errsrc", src.getAttribute("errsrc")) ;
    dst.setAttribute("onerror", "webcam_loaderror('"+src.getAttribute("webcam")+"');") ;
  }

  // Write text on the canvas
  function writetitle(cnv, ctx)
  {
    var showdate=cnv.getAttribute("showdate") ;
    if (showdate!="yes") return ;

    var alt=cnv.getAttribute("alt") ;
    var bgc=cnv.getAttribute("bgc") ;
    var fgc=cnv.getAttribute("fgc") ;
    var width=cnv.width;
    var d=new Date();
    var dates = d.toUTCString() ;
    alt=dates+" - "+alt ;

    ctx.save() ;
    if (getcapabilities()>CAP_CANVAS) {
      if (bgc!="none") {
        ctx.translate(0,0) ;
        ctx.fillStyle=bgc;
        ctx.fillRect(0,0,width,12) ;
      }
      if (getcapabilities()==CAP_CANVAS_HTML5) {
        ctx.fillStyle=fgc;
        ctx.font="8pt courier";
        ctx.textBaseline="top" ;
        ctx.fillText(alt,0,0);
      } else if (getcapabilities()==CAP_CANVAS_MOZ) {
        ctx.fillStyle=fgc;
        ctx.mozTextStyle="8pt courier";
        ctx.translate(0,10) ;
        ctx.mozDrawText(alt) ;
      }
    }
    ctx.restore() ;
  }

  // Process Canvas Image
  function processimage_canvas(img)
  {
    var cnv = document.createElement("canvas"); if (!cnv) return ;
    var ctx=cnv.getContext("2d") ; if (!ctx) return ;
    var flip=img.getAttribute("flip") ;
    var rotate=parseInt(img.getAttribute("rotate")) ;
    var height=img.height ;
    var width=img.width ;

    // Write the image to the context
    copyattributes(img,cnv) ;

    // May not need these ...
    cnv.width=img.width ;
    cnv.height=img.height ;

    var nh = 120;
    var nw = 80;

    ctx.save() ;
    if (rotate==90 || rotate==270 || rotate==-90) {
      // Rotate 90 / -90
      cnv.width=height ;
      cnv.height=width ;
      width=cnv.width ;
      heigh=cnv.height ;
      cnv.setAttribute('width', width);
      cnv.setAttribute('height', height);
      ctx.rotate(rotate * Math.PI / 180);
      if (flip=="horizontal") flip="vertical" ;
      else if (flip=="vertical") flip="horizontal" ;
      if (rotate==90) ctx.drawImage(img, 0, -width, width, height);
      else ctx.drawImage(img, -height, 0, width, height);
   } else if (rotate==180) {
      // Rotate 180
      ctx.rotate(rotate * Math.PI / 180);
      ctx.drawImage(img, -width, -height, width, height);
   } else if (getcapabilities()==CAP_CANVAS_HTML5) {
      // Just Draw Inage
      ctx.drawImage(img, 0, 0, width, height);
   } else {
      // Flip the Image
      if (flip=="horizontal") {
        for (v=0; v<width; v++)
          ctx.drawImage(img, v, 0, 1, height, width-v, 0, 1, height) ;
      } else if (flip=="vertical") {
        for (h=0; h<height; h++)
          ctx.drawImage(img, 0, h, width, 1, 0, height-h, width, 1) ;
      } else {
        // Just Draw Inage
        ctx.drawImage(img, 0, 0, width, height);
      }
    }
//ctx.scale(img,0.5,0.5);
//    ctx.restore() ;

    // HTML5 allows us to flip the image after rotation
    if (getcapabilities()==CAP_CANVAS_HTML5) {
      ctx.save() ;
      if (flip=="horizontal") {
        var imgl=ctx.createImageData(1,height) ;
        var imgr=ctx.createImageData(1,height) ;
        for (v=width/2; v>=0; v--) {
          imgl=ctx.getImageData(v,0,1,height) ;
          imgr=ctx.getImageData(width-v,0,1,height) ;
          ctx.putImageData(imgr, v, 0) ;
          ctx.putImageData(imgl, width-v, 0) ;
        }
      } else if (flip=="vertical") {
        var imgt=ctx.createImageData(width,1) ;
        var imgb=ctx.createImageData(width,1) ;
        for (h=height/2;h>=0;h--) {
          imgt=ctx.getImageData(0,h,width,1) ;
          imgb=ctx.getImageData(0,height-h,width,1) ;
          ctx.putImageData(imgb, 0, h) ;
          ctx.putImageData(imgt, 0, height-h) ;
        }
      }
      ctx.restore() ;
    }

    writetitle(cnv, ctx) ;
    return cnv ;
  }

  // Process Microsoft Image
  function processimage_microsoft(img)
  {
    var opts="" ;
    var flip=img.getAttribute("flip") ;
    var rotate=img.getAttribute("rotate") ;

    // Rotate the image
    switch (rotate) {
      case 90: 
        opts="rotation=1" ;
        break ;
      case 180: 
        opts="rotation=2" ;
        break ;
      case 270: 
      case -90: 
        opts="rotation=3" ;
        break ;
      default:
        break ;
    }

    // Flip the image if requested
    if (flip=="horizontal") {
      if (opts="") opts="mirror=1" ; else opts+=", mirror=1" ;
    } else if (flip=="vertical") {
      if (opts="") opts="mirror=1, rotation=2" ; else opts+=", mirror=1, rotation=2" ;
    }

    if (opts!="") img.style.filter="progid:DXImageTransform.Microsoft.BasicImage("+opts+")" ;
    return img ;
  }

  // Dispatch the processing to the appropriate function
  function processimage_dispatch(img)
  {
    if (getcapabilities()>=CAP_CANVAS)
      return processimage_canvas(img) ;
    if (getcapabilities()==CAP_MICROSOFT)
      return processimage_microsoft(img) ;
  }

  // Load / Schedule Update the Image
  function scheduleupdateimage(img)
  {
    var cache = new Image();
    var d = new Date() ;
    var stamp = d.getFullYear()+"_"+d.getMonth()+"_"+d.getDate()+"_"+
      d.getHours()+"_"+d.getMinutes()+"_"+d.getSeconds() ;

    copyattributes(img, cache) ;

    if (img.getAttribute("srcimg").indexOf("?")<0) {
      cache.src=img.getAttribute("srcimg")+"?stamp="+stamp ;
    } else {
      cache.src=img.getAttribute("srcimg")+"&stamp="+stamp ;
    }

    if (cache.complete) {
      img.parentNode.replaceChild(processimage_dispatch(cache), img) ;
    } else cache.onload = function() {       
      img.parentNode.replaceChild(processimage_dispatch(cache), img) ;
    }
  }

  // Perform automatic refresh / update
  function refresh()
  {
    var canvases = document.getElementsByTagName("canvas");
    var imgs = document.getElementsByTagName("img") ;
    if (dorefresh(canvases) || dorefresh(imgs)) setTimeout('refresh()', 2000) ;
  }

  function dorefresh(images)
  {
    var rmatch=0, refresh ;   
    if (!images) return (1==0) ;
    count=count+1 ;
    for (var i=0 ; i<images.length; i++) { 
      if (images[i].getAttribute("webcam") && images[i].getAttribute("refresh")) {
        rmatch=rmatch+1 ;
        refresh=parseInt(images[i].getAttribute("refresh")) ;
        refresh=refresh/2 ;
        if (refresh<1) refresh=1 ;
        if (images[i].getAttribute("graceful")=="yes" || refresh<6) {
          if (count>300) refresh=300 ; // 10m -> 5m intervals
          if (count>150) refresh=120 ; // 5m -> 2m intervals
          if (count>60) refresh=15 ; // 2m -> 30s intervals
          else if (count>15 && refresh<=2) refresh=refresh*5 ; // 30s -> 5*refresh intervals
        }
        if ((count/refresh) == parseInt(count/refresh)) scheduleupdateimage(images[i]) ;
      }
    }
    return (rmatch>0) ;
  }

  // Replace image with error image
  function webcam_loaderror(i)
  {
    var wc = document.getElementsByTagName("webcam") ;
    if (wc) for (j=0; j<wc.length; j++) 
      if (parseInt(wc[j].getAttribute("webcam"))==i) {
        wc[j].setAttribute("srcimg", wc[j].getAttribute("errsrc")) ;
        scheduleupdateimage(wc[j]) ;
      }
  }

  // Search for Images and update tags
  function webcam()
  {
    var images = document.getElementsByTagName("webcam");
    var refresh=0 ;
    for (var i=0 ; i<images.length; i++) { 
      if (images[i].getAttribute("refresh")>0) refresh=1 ;
      images[i].setAttribute("id","webcam") ;
      images[i].setAttribute("webcam",i) ;
      images[i].setAttribute("srcimg", images[i].getAttribute("src")) ;
      scheduleupdateimage(images[i]) ;
    }
    if (refresh==1) setTimeout('refresh()', 2000) ;
  }

 // Initialise
  count=0 ; errcount=0 ;
  if (window.addEventListener) { 
    window.addEventListener("load", webcam, false); 
  } else if (window.attachEvent) { 
    window.attachEvent("onload", webcam); 
  }

