if (!YAHOO.env.ua) {
	YAHOO.env.ua = function() {
		var o={
	
			/**
			 * Internet Explorer version number or 0.  Example: 6
			 * @property ie
			 * @type float
			 */
			ie:0,
	
			/**
			 * Opera version number or 0.  Example: 9.2
			 * @property opera
			 * @type float
			 */
			opera:0,
	
			/**
			 * Gecko engine revision number.  Will evaluate to 1 if Gecko 
			 * is detected but the revision could not be found. Other browsers
			 * will be 0.  Example: 1.8
			 * <pre>
			 * Firefox 1.0.0.4: 1.7.8   <-- Reports 1.7
			 * Firefox 1.5.0.9: 1.8.0.9 <-- Reports 1.8
			 * Firefox 2.0.0.3: 1.8.1.3 <-- Reports 1.8
			 * Firefox 3 alpha: 1.9a4   <-- Reports 1.9
			 * </pre>
			 * @property gecko
			 * @type float
			 */
			gecko:0,
	
			/**
			 * AppleWebKit version.  KHTML browsers that are not WebKit browsers 
			 * will evaluate to 1, other browsers 0.  Example: 418.9.1
			 * <pre>
			 * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the 
			 *                                   latest available for Mac OSX 10.3.
			 * Safari 2.0.2:         416     <-- hasOwnProperty introduced
			 * Safari 2.0.4:         418     <-- preventDefault fixed
			 * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
			 *                                   different versions of webkit
			 * Safari 2.0.4 (419.3): 419     <-- Current Safari release
			 * Webkit 212 nightly:   522+    <-- Safari 3.0 (with native SVG) should
			 *                                   be higher than this
			 *                                   
			 * </pre>
			 * http://developer.apple.com/internet/safari/uamatrix.html
			 * @property webkit
			 * @type float
			 */
			webkit:0
		};
	
		var ua=navigator.userAgent, m;
	
		// Modern KHTML browsers should qualify as Safari X-Grade
		if ((/KHTML/).test(ua)) {
			o.webkit=1;
		}
		// Modern WebKit browsers are at least X-Grade
		m=ua.match(/AppleWebKit\/([^\s]*)/);
		if (m&&m[1]) {
			o.webkit=parseFloat(m[1]);
		}
	
		if (!o.webkit) { // not webkit
			// @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
			m=ua.match(/Opera[\s\/]([^\s]*)/);
			if (m&&m[1]) {
				o.opera=parseFloat(m[1]);
			} else { // not opera or webkit
				m=ua.match(/MSIE\s([^;]*)/);
				if (m&&m[1]) {
					o.ie=parseFloat(m[1]);
				} else { // not opera, webkit, or ie
					m=ua.match(/Gecko\/([^\s]*)/);
					if (m) {
						o.gecko=1; // Gecko detected, look for revision
						m=ua.match(/rv:([^\s\)]*)/);
						if (m&&m[1]) {
							o.gecko=parseFloat(m[1]);
						}
					}
				}
			}
		}
		
		return o;
	}();
}

function parseArray(str,sep,typ) {
  var strs = [];
  var rslt = [];
  while (str.length > 0) {
    var p = str.indexOf(sep);
	if (p >= 0) {
	  var val = str.substring(0,p); 
  	  strs[strs.length] = val;
	  str = str.substring(p+1,str.length);
	} else {
	  val = str;
  	  strs[strs.length] = val;
	  str = "";	  
	}
  }
  for (i = 0; i < strs.length; i++) {
    if (typ == "int") var v = parseInt(strs[i]);
    if (typ == "float") var v = parseFloat(strs[i]);
	if (typ == "string") var v = strs[i];
    rslt[rslt.length] = v;
  }
  return(rslt);
}

/**
 * Image cropper widget.
 * Author: Julien Lecomte <jlecomte@yahoo-inc.com>
 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
 * Code licensed under the BSD License:
 * http://developer.yahoo.net/yui/license.txt
 * Requires YUI >= 2.3.
 *
 * @module image-cropper
 * @title Image cropper
 * @namespace YAHOO.widget
 * @requires yahoo,dom,event,dragdrop
 */

    // A few shortcuts
    var YD = YAHOO.util.Dom;
    var YE = YAHOO.util.Event;
    var YL = YAHOO.lang;

function rectToString(rect) {
  return(rect.x + "," + rect.y + "," + rect.w + "," + rect.h);
}

function sizePrintQuality(imgWidth,imgHeight, printWidth, printHeight) {
	var printArea = printWidth * printHeight;
	var MP = imgWidth * imgHeight / 1000000;
	
	if (MP >= 3) {
	  return ("Best");
	}
	
	if (MP >= 2) {
	  if (printArea <= 11*14) return("Best"); else return("Good");
	}
	
	if (MP >= 1.3) {
	  if (printArea <= 8*10) return("Best");
	  if (printArea <= 11*14) return("Good");
	  return("Poor");
	}
	
	if (MP >= 0.48) {
	  if (printArea <= 5*7) return("Best");
	  if (printArea <= 8*10) return("Good");
	  return("Poor");	
	}

	if (MP >= 0.3) {
	  if (printArea <= 4*6) return("Best");
	  if (printArea <= 5*7) return("Good");
	  return("Poor");	
	}
	
	return("Poor");

}


var hookRefCtr = 0;

/**
 * Image cropper widget.
 * @namespace YAHOO.widget
 * @class ImageCropper
 * @constructor
 * @param {String | HTMLImageElement} img Accepts a string to use as an ID or an actual DOM reference.
 * @param {Object} config Optional configuration object. The caller is responsible for making sure the
 *     config object contains values that make sense! For example, don't set x and w to exceed the total
 *     width of the image. Otherwise, unexpected things will happen (most likely, the specified xyratio
 *     will not be enforced properly) This object can contain the following keys:
 *         "x", "y", "w" and "h": default position and size
 *         "xyratio": ratio between width and height
 *
 */
 
function ftImageCropper( aimg ) {
  /**
   * Reference to the outer HTML element.
   * @property _outerElem
   * @type HTMLDivElement
   * @private
   */
  this.globalId = hookRefCtr;
  hookRefCtr++;
  this.outerElem = null;

  /**
   * Reference to the HTML element representing the cropping region.
   * @property _cropElem
   * @type HTMLDivElement
   * @private
   */
  this.cropElem = null;

  /**
   * Flag indicating whether the image cropper has been initialized.
   * @property _initialized
   * @type Boolean
   * @default false
   * @private
   */
   this.initialized = false;

  /**
   * Timer used to check whether the image has been loaded in WebKit.
   * @property _loadTimer
   * @private
   */
  this.loadTimer = null;

  // In case the caller passed in the id string of the image.
  this.img = YD.get( aimg );

  // Check the validity of the parameters passed to the constructor.
  if ( !this.img || this.img.tagName !== "IMG" ) {
      throw new Error( "Invalid argument" );
  }

  this.config = null;
  this.origSize = null;
  this.printSize = null;
  this.rotatePreview = false;
  this.maxMarginPercent = 0;
  this.initialCropRegion = null;

  /**
   * Fired when the crop region has been moved or resized.
   * @event onChangeEvent
   */
  this.onChangeEvent = new YAHOO.util.CustomEvent( "onChange" );

  
  return(this);
}		

ftImageCropper.prototype.initialize = function(aconfig) {	 
  this.config = aconfig;

  // Check the validity of the parameters passed to the constructor.
  if ( this.config && !YL.isObject( this.config ) ) throw new Error( "Invalid argument" );    

  // Figure out whether the rendered size of the image is known.
  // In WebKit, don't use the onload event. It seems unreliable.
  if ( YAHOO.env.ua.webkit ) {
    //YE.addListener( this.img, "load", this.init, this, true );
    var thisC = this;
	//alert(this.img);
    this.loadTimer = setInterval( function () {
      if ( thisC.img.width !== 0 || thisC.img.height !== 0 ) {
        clearInterval( thisC.loadTimer );
        thisC.init();
      }
    }, 100 );
  } else if ( YAHOO.env.ua.gecko && this.img.clientWidth == 0) {
    // The browser is either still loading the image, or it may be done,
    // but the image was not loaded (network problem, missing resource)
    // We don't need to differentiate between these two cases.
    YE.addListener( this.img, "load", this.init, this, true );
  } else if ( !this.img.complete || this.img.naturalWidth === 0) {
    // The browser is either still loading the image, or it may be done,
    // but the image was not loaded (network problem, missing resource)
    // We don't need to differentiate between these two cases.
    YE.addListener( this.img, "load", this.init, this, true );
  } else {
    // The image seems to be loaded.
    this.init();
  }  
}

    /**
     * Initialize the image cropper. Called when the specified image is loaded.
     * @method _init
     * @private
     */
ftImageCropper.prototype.setInitialRange = function(valuestr) {
  if (valuestr != "") {
    this.initialCropRegion = {};
	var varray = parseArray(valuestr,",","int");
	if (varray.length == 4) {
	  this.initialCropRegion.x = varray[0];
	  this.initialCropRegion.y = varray[1];
	  this.initialCropRegion.w = varray[2];
	  this.initialCropRegion.h = varray[3];
	}
  }
}
	 
ftImageCropper.prototype.init = function() {
  // make sure it's really okay to be here and everything is ready
  var ready = true;
  try {
    var w = this.img.width;
	var h = this.img.height;
    this.img.style.width = "auto";
    this.img.style.height = "auto";
	if (w == 0) ready = false;
  } catch (e) {
    ready = false;
  }
  
  if (!ready) {
    var thisC = this;
	window.setTimeout( function() {
	  thisC.init();
	}, 200);
	return;    
  }

  // setup a default config if print size was specified
  if (this.initialCropRegion) {
    this.config = {};
    var mult = this.origSize.width / this.img.width;	
    this.config.x = Math.floor(this.initialCropRegion.x / mult);
	this.config.y = Math.floor(this.initialCropRegion.y / mult);
	this.config.w = Math.floor(this.initialCropRegion.w / mult);
	this.config.h = Math.floor(this.initialCropRegion.h / mult);
	if (this.printSize) this.config.xyratio = this.calculateXYratio();
  } else
  if (this.printSize) {
    var imgsize = {};
    imgsize.width = this.img.width;
    imgsize.height = this.img.height;
	this.config = this.calculateDefaultCropParams(imgsize);
  }

  var mask, x, y, w, h, r, p, dd;

  if (this.initialized) {
    // This routine may be called several times in the case of Opera.
    return;
  }

  // There does not seem to be a cross-browser way of checking whether
  // an image has its natural size. Since this whole thing assumes the
  // image has its natural size, set its width and height to "auto".
  this.img.style.width = "auto";
  this.img.style.height = "auto";

  // Create the outer HTML element.
  this.outerElem = document.createElement( "DIV" );
  this.outerElem.className = "image-cropper";
  this.img.parentNode.replaceChild( this.outerElem, this.img );
  this.outerElem.appendChild( this.img );

  // Create a semi-opaque layer on top of the image.
  mask = document.createElement( "DIV" );
  mask.className = "cropMask";
  // Without specifying its width and height explicitly (instead of using
  // 100%), IE6 would not expand the mask to cover the entire image.
  // Setting its width and height does not hurt the other browsers.
  mask.style.width = this.img.clientWidth + "px";
  mask.style.height = this.img.clientHeight + "px";
  this.outerElem.appendChild( mask );

  // Create the crop region.
  this.cropElem = document.createElement( "DIV" );
  this.cropElem.className = "cropper";
  this.cropElem.style.background = "url(" + this.img.src + ")";
  this.outerElem.appendChild( this.cropElem );

  // Set the original size and position of the crop region.
  if ( this.config ) {
    w = this.config.w;
    h = this.config.h;
    x = this.config.x;
    y = this.config.y;
    r = this.config.xyratio;
  }
  
  if ( !YL.isNumber( w ) || w < 0 || w > this.img.clientWidth ) {
    // Invalid width. Defaults to 1/3 the image width.
    w = Math.floor( this.img.clientWidth / 3 );
  }

  if ( YL.isNumber( r ) && r > 0 ) h = r * w;

  // Invalid height. Defaults to 1/3 the image height.
  if ( !YL.isNumber( h ) || h < 0 || h > this.img.clientHeight )  h = Math.floor( this.img.clientHeight / 3 );

  // Invalid left. Defaults to centering the crop region.
  if ( !YL.isNumber( x ) || x < 0 || x + w > this.img.clientWidth ) x = ( this.img.clientWidth - w ) / 2;
  
  // Invalid top. Defaults to centering the crop region.
  if ( !YL.isNumber( y ) || y < 0 || y + h > this.img.clientHeight ) y = ( this.img.clientHeight - h ) / 2;

  this.setGeometry( this.cropElem, x, y, w, h );

  // Show the appropriate portion of the image in the crop region.
  p = this.getGeometry( this.cropElem );
  this.cropElem.style.backgroundPosition = ( -p.x ) + "px " + ( -p.y ) + "px";

  // Create the resize hooks.
  if ( !this.config || this.config.noresize !== true ) this.createHooks();

  // Set up the drag'n'drop...
  dd = new YAHOO.util.DD( this.cropElem );

  var thisC = this;
  dd.startDrag = function () {
    p = thisC.getGeometry( thisC.cropElem );
    this.resetConstraints();
    this.setXConstraint( p.x, thisC.img.clientWidth - p.x - p.w );
    this.setYConstraint( p.y, thisC.img.clientHeight - p.y - p.h );
  };

  dd.onDrag = function ( evt ) {
    p = thisC.getGeometry( thisC.cropElem );
    thisC.cropElem.style.backgroundPosition = ( -p.x ) + "px " + ( -p.y ) + "px";
  };

  dd.endDrag = function ( evt ) {
	thisC.cropChanged();  
  };

  this.initialized = true;
  this.cropChanged();  
}


	
ftImageCropper.prototype.setPrintSize = function(w,h) {
  // 0,0 nulls it out
  var dt = typeof w;
  if (dt == "string") {
    var arr = parseArray(w,"x","float");
	if (arr.length == 2) {
	  h = arr[0]; w = arr[1];
	}
  }
  
  if ((w == 0) && (h == 0)) {
    this.printSize = null;
	return;
  }
  
  this.printSize = {};
  if (w > h) {
    this.printSize.width = w;
    this.printSize.height = h;
  } else {
    this.printSize.width = h;
	this.printSize.height = w;
  }
}	

ftImageCropper.prototype.setOrigSize = function(w,h) {
  this.origSize = {};
  this.origSize.width = w;
  this.origSize.height = h;
}



    /**
     * Returns the pixel border width as an integer for
     * the specified border and the specified element.
     * @method _getPixelBorderWidth
     * @param {HTMLElement} el an actual DOM reference
     * @param {String} border "top", "right", "bottom" or "left"
     * @return {Number} border width
     * @private
     */
ftImageCropper.prototype.getPixelBorderWidth = function( el, border ) {

        var p, s, value;

        if ( YAHOO.env.ua.ie ) {

            switch ( border ) {
                case "top":
                    value = el.clientTop;
                    break;
                case "right":
                    value = el.offsetWidth - el.clientWidth - el.clientLeft;
                    break;
                case "bottom":
                    value = el.offsetHeight - el.clientHeight - el.clientTop;
                    break;
                case "left":
                    value = el.clientLeft;
                    break;
                default:
                    throw new Error( "Invalid border: " + border );
            }

        } else {

            switch ( border ) {
                case "top":
                    p = "border-top-width";
                    break;
                case "right":
                    p = "border-right-width";
                    break;
                case "bottom":
                    p = "border-bottom-width";
                    break;
                case "left":
                    p = "border-left-width";
                    break;
                default:
                    throw new Error( "Invalid border: " + border );
            }

            s = YD.getStyle( el, p );
            value = parseInt( s, 10 );
        }

        return value;
    }

    /**
     * Returns the position (relative to its offset parent) and size of the
     * specified element, independently of the box model used (i.e. this method
     * yields the same results in standards and quirks mode on all browsers).
     * The returned coordinates correspond to the position and size of the box
     * inside the element's borders (including the padding, but not including
     * the borders, which is what we care about in this widget)
     * @method _getGeometry
     * @param {HTMLElement} el an actual DOM reference
     * @return {Object} an object containing the members "x", "y", "w" and "h"
     * @private
     */
ftImageCropper.prototype.getGeometry = function( el ) {

        var ol, ot, blw, btw, pblw, pbtw;

        blw = this.getPixelBorderWidth( el, "left" );
        btw = this.getPixelBorderWidth( el, "top" );

        ol = el.offsetLeft + blw;
        ot = el.offsetTop + btw;

        if ( YAHOO.env.ua.gecko || YAHOO.env.ua.opera ) {

            pblw = this.getPixelBorderWidth( el.offsetParent, "left" );
            pbtw = this.getPixelBorderWidth( el.offsetParent, "top" );

            if ( YAHOO.env.ua.gecko ) {
                ol += pblw;
                ot += pbtw;
            } else if ( YAHOO.env.ua.opera ) {
                ol -= pblw;
                ot -= pbtw;
            }
        }

        return {
            x: ol,
            y: ot,
            w: el.clientWidth,
            h: el.clientHeight
        };
    }

    /**
     * Sets the specified element's position and size independently of the box
     * model used (i.e. this method yields the same results in standards and
     * quirks mode on all browsers). The specified coordinates correspond to
     * the position and size of the box inside the element's borders (including
     * the padding, but not including the borders, which is what we care about
     * in this widget)
     * @method _setGeometry
     * @param {HTMLElement} el an actual DOM reference
     * @param {Number} x left
     * @param {Number} y top
     * @param {Number} w width
     * @param {Number} h height
     * @private
     */
ftImageCropper.prototype.setGeometry = function( el, x, y, w, h ) {

        var p, d;

        el.style.position = "absolute";

        el.style.left = x + "px";
        el.style.top = y + "px";
        el.style.width = w + "px";
        el.style.height = h + "px";

        p = this.getGeometry( el );

        d = p.x - x;
        if ( d !== 0 ) {
            el.style.left = ( x - d ) + "px";
        }

        d = p.y - y;
        if ( d !== 0 ) {
            el.style.top = ( y - d ) + "px";
        }

        d = p.w - w;
        if ( d !== 0 ) {
            el.style.width = ( w - d ) + "px";
        }

        d = p.h - h;
        if ( d !== 0 ) {
            el.style.height = ( h - d ) + "px";
        }
    }


    /**
     * Creates the resize hooks.
     * @method _createHooks
     * @private
     */
ftImageCropper.prototype.createHooks = function() {

        var i, hook, dd, mouseX, mouseY, obj;

        for ( i = 0; i < 4 || ( !this.config || !YL.isNumber( this.config.xyratio ) || this.config.xyratio <= 0 ) && i < 8; i++ ) {

            // Create a resize hook...
            hook = document.createElement( "DIV" );
            this.cropElem.appendChild( hook );
			hook.id = "hook_" + this.globalId + "_" + i;

            // Set its class names...
            switch (i) {

                case 0:
                    YD.addClass( hook, "t" );
                    YD.addClass( hook, "l" );
                    YD.addClass( hook, "tl" );					
                    break;
                case 1:
                    YD.addClass( hook, "t" );
                    YD.addClass( hook, "r" );
                    YD.addClass( hook, "tr" );					
                    break;
                case 2:
                    YD.addClass( hook, "b" );
                    YD.addClass( hook, "l" );
                    YD.addClass( hook, "bl" );					
                    break;
                case 3:
                    YD.addClass( hook, "b" );
                    YD.addClass( hook, "r" );
                    YD.addClass( hook, "br" );					
                    break;
                case 4:
                    YD.addClass( hook, "t" );
                    YD.addClass( hook, "c" );
                    YD.addClass( hook, "tc" );					
                    break;
                case 5:
                    YD.addClass( hook, "m" );
                    YD.addClass( hook, "r" );
                    YD.addClass( hook, "mr" );					
                    break;
                case 6:
                    YD.addClass( hook, "b" );
                    YD.addClass( hook, "c" );
                    YD.addClass( hook, "bc" );					
                    break;
                case 7:
                    YD.addClass( hook, "m" );
                    YD.addClass( hook, "l" );
                    YD.addClass( hook, "ml" );					
                    break;
            }
			
            // Set up the hook drag'n'drop...
            dd = new YAHOO.util.DD( hook );
			dd.clickTimeThresh = 50;
			dd.padding = 10;
            dd.hasOuterHandles = true;			

            // Do this so the YUI DnD library does not move things on its own.
            // The downside is that we have to handle the constraints by hand.
            dd.alignElWithMouse = function ( el, iPageX, iPageY ) {};

            var thisC = this;
            dd.startDrag = function ( x, y ) {
                obj = thisC.getGeometry( thisC.cropElem );
                mouseX = x;
                mouseY = y;
            };

            dd.onDrag = function ( evt ) {

                var dx, dy, x, y, w, r, h, p;

                dx = YE.getPageX( evt ) - mouseX;
                dy = YE.getPageY( evt ) - mouseY;

                hook = this.getEl();

                if ( YD.hasClass( hook, "l" ) ) {
                    if ( dx < 0 ) {
                        dx = Math.max( -obj.x, dx );
                    } else {
                        dx = Math.min( obj.w, dx );
                    }
                    x = obj.x + dx;
                    w = obj.w - dx;
                } else if ( YD.hasClass( hook, "r" ) ) {
                    if ( dx < 0 ) {
                        dx = Math.max( -obj.w, dx );
                    } else {
                        dx = Math.min( thisC.img.clientWidth - obj.x - obj.w, dx );
                    }
                    x = obj.x;
                    w = obj.w + dx;
                } else {
                    dx = 0;
                    x = obj.x;
                    w = obj.w;
                }

                if ( YD.hasClass( hook, "t" ) ) {
                    if ( dy < 0 ) {
                        dy = Math.max( -obj.y, dy );
                    } else {
                        dy = Math.min( obj.h, dy );
                    }
                    y = obj.y + dy;
                    h = obj.h - dy;
                } else if ( YD.hasClass( hook, "b" ) ) {
                    if ( dy < 0 ) {
                        dy = Math.max( -obj.h, dy );
                    } else {
                        dy = Math.min( thisC.img.clientHeight - obj.y - obj.h, dy );
                    }
                    y = obj.y;
                    h = obj.h + dy;
                } else {
                    dy = 0;
                    y = obj.y;
                    h = obj.h;
                }

                if ( thisC.config && YL.isNumber( thisC.config.xyratio ) && thisC.config.xyratio > 0 ) {
                    // Handle the constraints.
                    r = thisC.config.xyratio;
                    h = Math.floor( w * r );
                    if ( YD.hasClass( hook, "t" ) ) {
                        y = obj.y + obj.h - h;
                        if ( y < 0 ) {
                            y = 0;
                            dy = -obj.y;
                            h = obj.h - dy;
                            w = Math.floor( h / r );
                            if ( YD.hasClass( hook, "l" ) ) {
                                dx = Math.floor( -dy / r );
                                x = obj.x - dx;
                            }
                        }
                    } else {
                        if ( y + h > thisC.img.clientHeight ) {
                            h = thisC.img.clientHeight - y;
                            w = Math.floor( h / r );
                            if ( YD.hasClass( hook, "l" ) ) {
                                dy = h - obj.h;
                                dx = Math.floor( dy / r );
                                x = obj.x - dx;
                            }
                        }
                    }
                }

                thisC.setGeometry( thisC.cropElem, x, y, w, h );

                p = thisC.getGeometry( thisC.cropElem );
                thisC.cropElem.style.backgroundPosition = ( -p.x ) + "px " + ( -p.y ) + "px";
            };

            dd.endDrag = function ( evt ) {
             	thisC.cropChanged();			
            };
        }
    }




    /**
     * Returns the current crop region.
     * @method getCropRegion
     * @return {Object} an object containing the members "x", "y", "w", and "h"
     */
ftImageCropper.prototype.getCropRegion = function () {
  return this.getGeometry( this.cropElem );
};

ftImageCropper.prototype.getOrigCropRegion = function () {
  var region = this.getGeometry( this.cropElem );
  if (this.origSize != null) {
    var ratio = this.origSize.width / this.img.width;
	region.x = Math.floor(region.x * ratio);
	region.y = Math.floor(region.y * ratio);
	region.w = Math.floor(region.w * ratio);
	region.h = Math.floor(region.h * ratio);			
  }
  return(region);
};

	
ftImageCropper.prototype.setXYratio = function(newr) {
  this.config.xyratio = newr;
}
	
ftImageCropper.prototype.getXYratio = function() {
  if (this.config.xyratio) return this.config.xyratio; else return(1);
}

ftImageCropper.prototype.calculateXYratio = function() {
  if (this.printSize == null) return(0);
 
  var landscape = true;
  if (this.origSize) {
    landscape = this.origSize.width > this.origSize.height; 
  } else
  if (this.initialized) {
    landscape = this.img.width > this.img.height;
  } 
  
  if (this.printSize) {
    if (landscape) {
      var ratio = this.printSize.height / this.printSize.width;
    } else {
      var ratio = this.printSize.width / this.printSize.height;	
    }    
  } else {
    if (landscape) {
	  var ratio = 4/6;
	} else {
	  var ratio = 6/4;
	}  
  }
  
  if (this.rotatePreview) ratio = 1 / ratio;
  return(ratio);
}

ftImageCropper.prototype.calculateDefaultCropParams = function(previewSize) {
    var params = {};
	if (this.printSize == null) return;
	params.xyratio = this.calculateXYratio();
    var rect = this.getMaxCropRect();		
	params.x = rect.x;
	params.y = rect.y;
	params.w = rect.w;
	params.h = rect.h;
	
	return params;
}

ftImageCropper.prototype.getMaxCropRect = function() {
	var landscape = this.img.width > this.img.height;
	var paperWidth = this.printSize.width;
	var paperHeight = this.printSize.height;
	
	if (this.rotatePreview) landscape = !landscape;	
    if (!landscape) {
	  paperWidth = this.printSize.height;
	  paperHeight = this.printSize.width;
	}

    var ImageRatio = 0, PaperRatio = 0;
    if (landscape) {
      imageRatio = this.origSize.width / this.origSize.height;
      paperRatio = paperWidth / paperHeight;
    } else {
      imageRatio = this.origSize.height / this.origSize.width;
      paperRatio = paperHeight / paperWidth;
    }

    var dDestWidth = 0.0, dDestHeight = 0.0;
    if (paperRatio > imageRatio) {
      if (landscape) {
        dDestWidth = this.img.width;
        dDestHeight = dDestWidth / paperRatio;
	  } else {
        dDestHeight = this.img.height;
        dDestWidth = dDestHeight / paperRatio;
	  }
	} else {
      if (landscape) {
        dDestHeight = this.img.height;
        dDestWidth = dDestHeight * paperRatio;
	  } else {
        dDestWidth = this.img.width;
        dDestHeight = dDestWidth * paperRatio;
	  }
	}

    var destWidth = Math.floor(dDestWidth);
    var destHeight = Math.floor(dDestHeight);
    if (this.maxMarginPercent != 0) {
	  var mult = 1 - (this.maxMarginPercent / 100);
	  destWidth = Math.floor(destWidth * mult);
	  destHeight = Math.floor(destHeight * mult);	  
	}

    wdif = Math.floor((this.img.width - destWidth) / 2);
    hdif = Math.floor((this.img.height - destHeight) / 2);
	
	var cRect = {};
    cRect.x = wdif;
	cRect.y = hdif;
	cRect.w = destWidth;
	cRect.h = destHeight;

	return(cRect);
}

ftImageCropper.prototype.update = function() {
  this.config.xyratio = this.calculateXYratio();
  if (this.printSize) {
	var rect = this.getMaxCropRect();
    this.refreshCrop(rect);  
	this.removeHooks();	
	this.createHooks();			
  } else {
    var crect = this.getCropRegion();
	if ( ((crect.x == 0) && (crect.w == this.img.width)) || ((crect.y == 0) && (crect.h == this.img.height)) ) {
      var x = Math.floor(this.img.width * 0.1);
      var y = Math.floor(this.img.height * 0.1);
      var w = Math.floor(this.img.width * 0.8);
      var h = Math.floor(this.img.height * 0.8);
	} else {
	  var x = crect.x;
	  var y = crect.y;
	  var w = crect.w;
	  var h = crect.h;
	}
	var rect = {};
	rect.x = x;
	rect.y = y;
	rect.w = w;
	rect.h = h;
	this.refreshCrop(rect);
	this.removeHooks();	
	this.createHooks();		
  }
  this.cropChanged();  
}

ftImageCropper.prototype.removeHooks = function() {
  for (var i=0; i<= 7; i++) {
    var hooke = document.getElementById("hook_" + this.globalId + "_" + i);
	if (hooke) this.cropElem.removeChild(hooke);
  }
}

ftImageCropper.prototype.rotateCrop = function() {
	if (this.printSize == null) return;
	
	this.rotatePreview = !this.rotatePreview;
	this.config.xyratio = this.calculateXYratio();
	var rect = this.getMaxCropRect();
    this.refreshCrop(rect);
	this.cropChanged();
}

ftImageCropper.prototype.refreshCrop = function(rect) {
  this.setGeometry( this.cropElem, rect.x, rect.y, rect.w, rect.h );
  p = this.getGeometry( this.cropElem );
  this.cropElem.style.backgroundPosition = ( -p.x ) + "px " + ( -p.y ) + "px";	
}

ftImageCropper.prototype.cropChanged = function() {
  this.onChangeEvent.fire();	
}

ftImageCropper.prototype.getPrintQuality = function() {
  if (this.printSize != null) {
    var rect = this.getOrigCropRegion();
	return(sizePrintQuality(rect.w,rect.h,this.printSize.width,this.printSize.height));
  } else {
    return("Good");
  }
}

ftImageCropper.prototype.initialzeSelectOptions = function(sel) {
  var iSel = YD.get( sel );
  var optns = iSel.options;
  optns[optns.length] = new Option("Wallets", "2.5x3.5");
  optns[optns.length] = new Option("3.5x5", "3.5x5");
  optns[optns.length] = new Option("4x6", "4x6");
  optns[optns.length] = new Option("5x7", "5x7");
  optns[optns.length] = new Option("8x10", "8x10");
  optns[optns.length] = new Option("8x12", "8x12");
  optns[optns.length] = new Option("11x14", "11x14");
  optns[optns.length] = new Option("16x20", "16x20");
  optns[optns.length] = new Option("18x24", "18x24");
  optns[optns.length] = new Option("20x30", "20x30");
  optns[optns.length] = new Option("24x36", "24x36");                    
  optns[optns.length] = new Option("30x40", "30x40");
  optns[optns.length] = new Option("Un-restricted", "0x0");    
  var ndx = 2;
  if (this.printSize != null) {
    var sz = this.printSize.height + 'x' + this.printSize.width;
	for (i = 0; i<optns.length; i++) {
	  var opt = optns[i];
	  if (opt.value == sz) ndx = i;
	}
    if (ndx < 0) ndx = 2;
  } else {
    ndx = 12;
  }
  iSel.selectedIndex = ndx;  
}
