/**
 * LX' ImageCrop v1.5
 *
 *  Authors: Alexander Schulze
 *  License: GPL v2 or compatible
 *           http://www.fsf.org/licenses/gpl.html
 *  Contact: webmaster@lxhome.de
 *           http://www.lxhome.de
 *
 * This script provides a basic functionality to draw crop areas on an
 * image and to paste necessary size information into a form, which
 * can then be posted to a server side script to crop an image to the
 * specified size.
 *
 *********************************************************************
 *
 * History of Changes:
 * v1.5   Bugfix:  drawing selection from bottom upwards now returns
 *                 correct values
 * v1.4   Feature: horizontal scrolling is now allowed
 *        Bugfix:  positioning with keys returned wrong values
 *        Bugfix:  shading of maximized selection after already
 *                 drawing a selection
 *        Misc:    better XHTML support
 * v1.3   Feature: action frame
 * v1.2   Bugfix:  selection can be expanded to the top when document
 *                 is scrolled
 *        Feature: selection can be finished when cursor is out of
 *                 the image
 *        Feature: clear selection with DEL and ESC, too
 * v1.1   Bugfix:  moving without selection
 *        Bugfix:  selection problem in Firefox
 *        Feature: moving and resizing the selection faster using the
 *                 SHIFT key
 *        Feature: switched resizing the selection to PGUP/PGDN
 *                 because of "find as you type" funtionality in some
 *                 browsers
 *        Feature: biggest possible selection using HOME key
 *        Feature: clear selection using END key
 * v1.0   first release
 *
 *********************************************************************
 *
 * Works with (at least):
 * - modern browsers (Gecko derivates, Opera, Konqueror, IE7)
 * - IE6 (without action frame)
 *
 *********************************************************************
 *
 * Usage:
 * See http://www.lxhome.de/eng/scripts/imagecrop
 *
 *********************************************************************
 *
 * Restrictions:
 * - computing of the correct values fails if any parent element in
 *   the DOM tree has a special positioning (absolute, relative)
 *
 *********************************************************************
 *
 * Disclaimer:
 * 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 2 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, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */

var Wand = window.document.getElementById('wand');
var Crop = window.document.getElementById('crop');
var Act  = window.document.getElementById('actionarea');

var C_T  = window.document.getElementById('c_t').style;
var C_B  = window.document.getElementById('c_b').style;
var C_L  = window.document.getElementById('c_l').style;
var C_R  = window.document.getElementById('c_r').style;

var icl  = document.getElementById('ic_left');
var ict  = document.getElementById('ic_top');
var icw  = document.getElementById('ic_width');
var ich  = document.getElementById('ic_height');

// wird häufiger gebraucht, daher kürzer als Property
Crop.width  = parseInt ( Crop.style.width  );
Crop.height = parseInt ( Crop.style.height );

// Startpunkt der Selektion und deren Höhe und Breite
var startX, startY;
var scrollX, scrollY;
var s_height, s_width;

// Seitenverhältnis der Selektion sowie deren vorgeschriebener Wert
var aspectRatio;
var fixAspectRatio = 0;

var WandAction = false;

// Events registrieren
document.onmousedown = doNothing;
document.onmouseup   = doNothing;
document.onmousemove = doNothing;

Act.onmousedown = selectStart;
Act.onmouseup   = selectEnd;
Act.onmousemove = selectSize;

Wand.onmousedown = moveStart;
Wand.onmouseup   = moveEnd;
Wand.onmousemove = moveMove;

// Tastendrücke an diese Funktion leiten
document.onkeydown = keyAction;

// Scrollposition bestimmen
function getScrollPosition()
{
    scrollX = ( typeof window.pageXOffset == 'undefined' )
              ? document.body.scrollLeft
              : window.pageXOffset;

    scrollY = ( typeof window.pageYOffset == 'undefined' )
              ? document.body.scrollTop
              : window.pageYOffset;
}

function doNothing()
{
    return false;
}

function selectStart ( e )
{
    e = ( !e ) ? window.event : e;

    getScrollPosition();

    if (      e.clientX < Crop.offsetLeft - scrollX )
        startX = Crop.offsetLeft;
    else if ( e.clientX > Crop.offsetLeft - scrollX + Crop.width )
        startX = Crop.offsetLeft + Crop.width;
    else
        startX = e.clientX + scrollX;

    if (      e.clientY < Crop.offsetTop - scrollY )
        startY = Crop.offsetTop;
    else if ( e.clientY > Crop.offsetTop - scrollY + Crop.height )
        startY = Crop.offsetTop + Crop.height;
    else
        startY = e.clientY + scrollY;

    Wand.style.width  = '0px';
    Wand.style.height = '0px';
    Wand.style.top    = '0px';
    Wand.style.left   = '0px';

    WandAction     = true;
    Wand.className = 'crosshair';

    Wand.onmousedown   = selectStart;
    Wand.onmouseup     = selectEnd;
    Wand.onmousemove   = selectSize;

    document.onmouseup = selectEnd;

    icl.value = 0;
    ict.value = 0;
    icw.value = 0;
    ich.value = 0;

    C_T.height = '0px';
    C_L.width  = '0px';
    C_R.width  = '0px';
    C_B.height = '0px';
}

function selectSize ( e )
{
    if ( typeof WandAction == 'undefined' || !WandAction )
        return;

    e = ( !e ) ? window.event : e;

    if (      e.clientX < Crop.offsetLeft - scrollX )
        s_width = Math.max ( 0,              startX - Crop.offsetLeft );
    else if ( e.clientX > Crop.offsetLeft - scrollX + Crop.width )
        s_width = Math.max ( 0, Crop.width - startX + Crop.offsetLeft );
    else
        s_width = Math.abs ( startX - e.clientX - scrollX );

    if (      e.clientY < Crop.offsetTop - scrollY )
        s_height = Math.max ( 0,               startY - Crop.offsetTop );
    else if ( e.clientY > Crop.offsetTop - scrollY + Crop.height )
        s_height = Math.max ( 0, Crop.height - startY + Crop.offsetTop );
    else
        s_height = Math.abs ( startY - e.clientY - scrollY );

    if ( s_height == 0 && s_width == 0 )
    {
        C_T.height = '0px';
        C_L.width  = '0px';
        C_R.width  = '0px';
        C_B.height = '0px';

        Wand.style.width  = '0px';
        Wand.style.height = '0px';
        Wand.style.top    = '0px';
        Wand.style.left   = '0px';

        return;
    }

    if ( fixAspectRatio != 0 )
    {
        if (      s_width / s_height > fixAspectRatio )
            s_width  = Math.round ( fixAspectRatio * s_height );
        else if ( s_width / s_height < fixAspectRatio )
            s_height = Math.round ( s_width / fixAspectRatio  );
    }

    Wand.style.width  = s_width  + 'px';
    Wand.style.height = s_height + 'px';

    C_L.height = s_height + 'px';
    C_R.height = s_height + 'px';

    // waagerecht
    if ( startX > e.clientX + scrollX )
    {
        Wand.style.left = startX - s_width + 'px';
        C_L.width       = startX - s_width - Crop.offsetLeft + 'px';
    }
    else
    {
        Wand.style.left = startX + 'px';
        C_L.width       = startX - Crop.offsetLeft + 'px';
    }

    // senkrecht
    if ( startY > e.clientY + scrollY )
    {
        Wand.style.top = startY - s_height + 'px';
        C_T.height     = startY - s_height - Crop.offsetTop + 'px';
        C_L.top        = startY - s_height - Crop.offsetTop + 'px';
        C_R.top        = startY - s_height - Crop.offsetTop + 'px';
    }
    else
    {
        Wand.style.top = startY + 'px';
        C_T.height     = startY - Crop.offsetTop + 'px';
        C_L.top        = startY - Crop.offsetTop + 'px';
        C_R.top        = startY - Crop.offsetTop + 'px';
    }

    C_R.width  = Crop.width  - parseInt ( C_L.width  ) - s_width  + 'px';
    C_B.height = Crop.height - parseInt ( C_T.height ) - s_height + 'px';
}

function selectEnd ( e )
{
    e = ( !e ) ? window.event : e;

    if ( s_width  == 0 || s_width  == 'undefined' ||
         s_height == 0 || s_height == 'undefined' ||
         startX == e.clientX + scrollX ||
         startY == e.clientY + scrollY )
    {
        icl.value = 0;
        ict.value = 0;
        icw.value = 0;
        ich.value = 0;

        C_T.height = '0px';
        C_L.width  = '0px';
        C_R.width  = '0px';
        C_B.height = '0px';
    }
    else
    {
        icl.value   = ( startX > e.clientX + scrollX )
                      ? startX - Crop.offsetLeft - s_width
                      : startX - Crop.offsetLeft;
        ict.value   = ( startY > e.clientY + scrollY )
                      ? startY - Crop.offsetTop - s_height
                      : startY - Crop.offsetTop;
        icw.value   = s_width;
        ich.value   = s_height;

        if ( WandAction )
        {
            Wand.className = 'move';

            Wand.onmousedown   = moveStart;
            Wand.onmouseup     = moveEnd;
            Wand.onmousemove   = moveMove;
        }
    }

    document.onmouseup = doNothing;
    aspectRatio = s_height / s_width;
    WandAction  = false;
}

function moveStart ( e )
{
    e = ( !e ) ? window.event : e;

    getScrollPosition();

    WandAction = true;

    Act.onmousedown = moveStart;
    Act.onmouseup   = moveEnd;
    Act.onmousemove = moveMove;

    startX = e.clientX;
    startY = e.clientY;
}

function moveMove ( e )
{
    if ( !WandAction )
        return;

    e = ( !e ) ? window.event : e;

    var t = parseInt ( Wand.style.top  ) - startY + e.clientY;
    var l = parseInt ( Wand.style.left ) - startX + e.clientX;

    // prüfen, ob Selektion außerhalb des Bildes geht
    if ( t - Crop.offsetTop  < 0 )
        t = Crop.offsetTop;

    if ( l - Crop.offsetLeft < 0 )
        l = Crop.offsetLeft;

    if ( t - Crop.offsetTop  + s_height > Crop.height )
        t = Crop.height - s_height + Crop.offsetTop;

    if ( l - Crop.offsetLeft + s_width  > Crop.width  )
        l = Crop.width  - s_width  + Crop.offsetLeft;

    Wand.style.top  = t + 'px';
    Wand.style.left = l + 'px';

    startX = e.clientX;
    startY = e.clientY;

    C_T.height = t - Crop.offsetTop  + 'px';
    C_L.top    = t - Crop.offsetTop  + 'px';
    C_L.width  = l - Crop.offsetLeft + 'px';
    C_R.top    = t - Crop.offsetTop  + 'px';
    C_R.width  = Crop.width  - parseInt ( C_L.width  ) - s_width  + 'px';
    C_B.height = Crop.height - parseInt ( C_T.height ) - s_height + 'px';
}

function moveEnd ( e )
{
    e = ( !e ) ? window.event : e;

    var t = parseInt ( Wand.style.top  ) - startY + e.clientY;
    var l = parseInt ( Wand.style.left ) - startX + e.clientX;

    ict.value = t - Crop.offsetTop;
    icl.value = l - Crop.offsetLeft;

    Act.onmousedown = selectStart;
    Act.onmouseup   = selectEnd;
    Act.onmousemove = selectSize;

    WandAction = false;
}

function keyAction ( e )
{
    e = ( !e ) ? window.event : e;

    if ( document.all )
        var k = e.keyCode;
    else
        var k = e.which;

    if ( s_height == 0 || s_width  == 0 )
        return

    if ( e.shiftKey )
        value = 10;
    else
        value = 1;

    // links
    if ( k == 37 && parseInt ( Wand.style.left ) - Crop.offsetLeft - value >= 0 )
    {
        Wand.style.left = ( parseInt ( Wand.style.left ) - value ) + 'px';
        icl.value = parseInt ( icl.value ) - value;

        C_L.width = parseInt ( C_L.width ) - value + 'px';
        C_R.width = parseInt ( C_R.width ) + value + 'px';
    }

    // hoch
    if ( k == 38 && parseInt ( Wand.style.top ) - Crop.offsetTop - value >= 0 )
    {
        Wand.style.top = ( parseInt ( Wand.style.top ) - value ) + 'px';
        ict.value = parseInt ( ict.value ) - value;

        C_T.height = parseInt ( C_T.height ) - value + 'px';
        C_B.height = parseInt ( C_B.height ) + value + 'px';
        C_R.top    = parseInt ( C_R.top    ) - value + 'px';
        C_L.top    = parseInt ( C_L.top    ) - value + 'px';
    }

    // rechts
    if ( k == 39 &&
         parseInt ( Wand.style.left ) - Crop.offsetLeft + s_width + value <= Crop.width )
    {
        Wand.style.left = ( parseInt ( Wand.style.left ) + value ) + 'px';
        icl.value = parseInt ( icl.value ) + value;

        C_L.width = parseInt ( C_L.width ) + value + 'px';
        C_R.width = parseInt ( C_R.width ) - value + 'px';
    }

    // runter
    if ( k == 40 &&
         parseInt ( Wand.style.top ) - Crop.offsetTop + s_height + value <= Crop.height )
    {
        Wand.style.top = ( parseInt ( Wand.style.top ) + value ) + 'px';
        ict.value = parseInt ( ict.value ) + value;

        C_T.height = parseInt ( C_T.height ) + value + 'px';
        C_B.height = parseInt ( C_B.height ) - value + 'px';
        C_R.top    = parseInt ( C_R.top    ) + value + 'px';
        C_L.top    = parseInt ( C_L.top    ) + value + 'px';
    }

    // proportional vergrößern (PGUP)
    if ( ( k == 33 ) &&
         ( parseInt ( Wand.style.top  ) - Crop.offsetTop  + s_height + value <= Crop.height ) &&
         ( parseInt ( Wand.style.left ) - Crop.offsetLeft + s_width  + value <= Crop.width  ) )
    {
        s_width += value;
        s_height = Math.round ( aspectRatio * s_width );

        Wand.style.width  = s_width  + 'px';
        Wand.style.height = s_height + 'px';

        icw.value = s_width;
        ich.value = s_height;

        C_R.width  = Crop.width  - parseInt ( C_L.width  ) - s_width  + 'px';
        C_B.height = Crop.height - parseInt ( C_T.height ) - s_height + 'px';
        C_L.height = s_height + 'px';
        C_R.height = s_height + 'px';
    }

    // proportional verkleinern (PGDN)
    if ( k == 34 && s_height > value && s_width > value )
    {
        s_width -= value;
        s_height = Math.round ( aspectRatio * s_width );

        Wand.style.width  = s_width  + 'px';
        Wand.style.height = s_height + 'px';

        icw.value = s_width;
        ich.value = s_height;

        C_R.width  = Crop.width  - parseInt ( C_L.width  ) - s_width  + 'px';
        C_B.height = Crop.height - parseInt ( C_T.height ) - s_height + 'px';
        C_L.height = s_height + 'px';
        C_R.height = s_height + 'px';
    }

    // größtmögliche Auswahl treffen (POS1)
    if ( k == 36 )
    {
        s_width  = Crop.width;
        s_height = Crop.height;

        if ( fixAspectRatio != 0 )
        {
            if (      s_width / s_height > fixAspectRatio )
                s_width  = Math.round ( fixAspectRatio * s_height );
            else if ( s_width / s_height < fixAspectRatio )
                s_height = Math.round ( s_width / fixAspectRatio  );
        }

        icl.value = 0;
        ict.value = 0;
        ich.value = s_height;
        icw.value = s_width;

        Wand.style.top    = Crop.offsetTop  + 'px';
        Wand.style.left   = Crop.offsetLeft + 'px';
        Wand.style.height = s_height + 'px';
        Wand.style.width  = s_width  + 'px';

        C_T.height = '0px';
        C_L.width  = '0px';
        C_L.top    = '0px';
        C_R.top    = '0px';
        C_L.height = s_height + 'px';
        C_R.height = s_height + 'px';
        C_R.width  = Crop.width  - s_width  + 'px';
        C_B.height = Crop.height - s_height + 'px';

        Wand.className = 'move';

        Wand.onmousedown = moveStart;
        Wand.onmouseup   = moveEnd;
        Wand.onmousemove = moveMove;
    }

    // Auswahl aufheben (END, ESC, ENTF)
    if ( k == 35 || k == 27 || k == 46 )
    {
        Wand.style.width  = '0px';
        Wand.style.height = '0px';
        Wand.style.top    = '0px';
        Wand.style.left   = '0px';

        Wand.onmousedown = selectStart;
        Wand.onmouseup   = selectEnd;
        Wand.onmousemove = selectSize;

        icl.value = 0;
        ict.value = 0;
        icw.value = 0;
        ich.value = 0;

        C_T.height = '0px';
        C_L.width  = '0px';
        C_R.width  = '0px';
        C_B.height = '0px';
    }
}
