/** 
 * @private
 * Utility-Class that helps capture webcam images.
 * 
 * It's needed to declare a text with 'WEBCAM_INIT' on the varname-field, to get the webcam container.
 * It's also needed to declare two buttons with 'JS_WEBCAM_SNAP' - (captures a preview).
 * And 'JS_WEBCAM_RESET' - (clears the freeze).
 */
sol.define("sol.common.forms.Webcam", {
    
  /**
   * Initialize the webcam
   * @param {Object} config Configuration
   */
  initialize: function (config) {
    
    var me = this,
        webcamContainer = $var(config.varNameContainer),
        resetBtn = $var(config.varNameBtnReset),
        snapBtn = $var(config.varNameBtnSnap),
        sBrowser, 
        sUsrAg = navigator.userAgent,
        objectElements,
        forceFlash = false;
        
    
    me.captured = false;
    me.varNameBtnSnap = config.varNameBtnSnap;
    me.varNameBtnReset = config.varNameBtnReset;
    me.varNameContainer = config.varNameContainer;
    me.webcamContainer = webcamContainer;

    sol.common.forms.Utils.initializeIxSession();
    
    if (resetBtn) {
      resetBtn.disabled = true;
    }
    
    if (snapBtn) {
      snapBtn.disabled = false;
    }
    
    if (sUsrAg.indexOf("Chrome/") > -1) {
      sBrowser = "Google Chrome";
    }
    
    // https?
    if (window.location.protocol == "http:" && sBrowser == "Google Chrome") {
      forceFlash = true;
    }
    
    if (webcamContainer) {
      
      Webcam.set({
        width: config.width,
        height: config.height,
        dest_width: config.dest_width,
        dest_height: config.dest_height,
        crop_width: config.crop_width,
        crop_height: config.crop_height,
        image_format: config.image_format,
        jpeg_quality: config.jpeg_quality,
        swfURL: config.swfURL,
        force_flash: forceFlash,
        fps: config.fps
      });
      
      var webcamConnected = undefined;
      Webcam.on("error", function (err) {
        webcamConnected = false;
      });

      Webcam.attach(config.varNameContainer);

      var container = document.getElementById(config.varNameContainer);
      var childNodes = container && Array.prototype.slice.call(container.childNodes);
      var children = childNodes.length === 2 && childNodes[1].children;
      var swfObject = (children && children.length > 0 && children[0].tagName === "OBJECT") && children[0];
      swfObject && childNodes[1].classList.add("sol-webcam");

      objectElements = webcamContainer.getElementsByTagName("object");
      if (objectElements && (objectElements.length > 0)) {
        objectElements[0].value = "";
      }
      me.intervalUntil(
        function () {
          return true;
        },
        function () { // until webcam is loaded or loading failed
          return (Webcam.loaded || typeof webcamConnected !== "undefined");
        },
        function () {
          function removeSwf() {
            if (!config.showIfNoCam) {
              webcamContainer.style.display = "none";
              $hide(config.varNameContainer);
            }
            console.log("No webcam found");

            $hide(config.varNameBtnSnap);
            $hide(config.varNameBtnReset);
            swfObject && swfObject.parentElement.removeChild(swfObject);
          }
          (typeof webcamConnected !== "undefined") &&
            removeSwf();
        },
        50,
        { name: "loading webcam library", logging: true }
      );
    }
  },
  /**
   * freeze camera, user get's a preview picture and swap the button sets.
   */
  snap: function () {
    var me = this;
    me.state = true;
    Webcam.freeze();
    me.toggle();
  },
  /**
   * Cancel preview freeze and return to live camera feed and swap buttons back.
   */
  reset: function () {
    var me = this;
    me.state = false;
    me.capture = false;
    Webcam.unfreeze();
    me.toggle();
  },
  
  toggle: function () {
    var me = this;
    $var(me.varNameBtnSnap).disabled = !$var(me.varNameBtnSnap).disabled;
    $var(me.varNameBtnReset).disabled = !$var(me.varNameBtnReset).disabled;
  },
  
  /**
   * Saves the snapshot in the folder that was selected for this workflow.
   * @param {Function} saveFunc Save Function
   */
  savePicture: function (saveFunc) {
    var me = this;
    
    if (me.state && !me.captured) {
      Webcam.snap(function (data_uri) {
        var image;
              
        ELOF.showLoadingDiv();
        image = data_uri.replace(/^data:image\/(jpeg|png|gif|bmp);base64,/, "");
              
        if (saveFunc(image)) {
          console.info("Successful saved");
          me.captured = true;
        } else {
          me.reset();
        } 
      });
    }
  },
  //small wrapper around interval functions
  //This function is 100% decoupled from any ELO-specifics and can be used in pure Javascript environments
  /*
    f: function to perform work
    until: function to check if f should be run again or not
    after: function to run after until conditions were met
    intervalTime: time in ms (interval runs every x ms)
    params: {
      f: any            pass f any param you like
      f_message:String  console.log before f is called 
      until:any   pass any any param you like
      until_message: String  console.log before until is called
      conditionmet_message:String  console.log if contition is met
      after:any   pass after any param you like
      afterafter_message:String   console.log after after was called
      logging: Boolean    enables logging if set to true
      maxtries: Integer     how often the f function will be executed before the interval is stopped
      name: String          name in logger
    }
    if the messages are defined as empty strings, no console-logging will be done.

    Of course the execution time of f and until is synchronized. f always runs before until.
    returns a function, which can later be used to stop the interval, if the until condition seems to never reach an end
  */
  intervalUntil: function (f, until, after, intervalTime, params) {
    var intervals = [], parms = params || {}, maxTries = params.maxtries - 1, executed = 0, 
        allowF = true, allowUntil = false; //for synchronizing f and until
    function logIt(message, paramMsg) {
      parms.logging && paramMsg !== "" && console.log("Interval " + (parms.name ? "'" + parms.name + "'" : "") + ":" + (paramMsg || message));
    }

    intervals.push(
      setInterval(  //setInterval is a standard Javascript function
        function () {
          if (!allowF) {
            return;
          }
          logIt("performing work", parms.f_message);
          f && f(parms.f);
          executed++;
          allowF = false;
          allowUntil = true;
        }, intervalTime
      )
    );
    intervals.push(
      setInterval(
        function () {
          if (!allowUntil) {
            return;
          }
          logIt("until condition met?", parms.until_message);
          if (parms.maxtries && maxTries-- === 0 || until && until(parms.until)) {
            logIt(maxTries === 0 ? "Tried too many times:" + parms.maxTries : "until condition met!", maxTries === 0 ? parms.maxTriesMessage : parms.conditionmet_message);
            intervals.forEach(clearInterval);   //clearInterval is a standard Javascript function
            after && after(parms.after);
            logIt("after callback executed. Interval finished & closed after " + executed + " cycles!", parms.afterafter_message);
          }
          allowF = true;
          allowUntil = false;
        }, intervalTime
      )
    );
    return function () {
      intervals.forEach(clearInterval);
      logIt("closed manually after " + executed + " cycles!", parms.clearedManually);
    };
  },
});