/*
 * @copyright       © Copyright 2006-2010, epages GmbH, All Rights Reserved.
 *
 * @module          ep.fn.contextOrientation
 */

/*jslint browser:true*/
/*global define*/
define("ep/fn/contextorientation", [
    "jquery",
    "ep"
], function ($, ep) {

    'use strict';

    var xExpr = /(left|center|right)/,
        yExpr = /(top|middle|bottom)/;

    ep.fn.extend({
        /**
         * Set position to each of the set of matched elements related to an event or other element.
         *
         * The `.contextOrientation()` method adds/removes a busy layer to/from each of the set of
         * matched elements.
         *
         * ### Examples
         * Show a tooltip on click the image and position it right of the click position.
         *
         * JavaScript:
         *
         *     $('#context')
         *         .on( 'click', function( event ) {
         *             ep(this)
         *                 .show()
         *                 .contextOrientation( event, 'right' );
         *         });
         *
         * HTML:
         *
         *     <body>
         *       <img id="context" src="example.jpg" alt="example picture"/>
         *       <div id="tooltip">
         *         <h1>Example</h1>
         *         <span>Tooltip informations ...</span>
         *       </div>
         *     </body>
         *
         * CSS:
         *
         *     #tooltip {
         *         position: absolute;
         *         width: 100px;
         *     }
         *
         *
         * @param {String,Object}  action A selector, element or event as context to orient.
         * @param {String} orient  A vertical and/or horizontal position: middle, bottom, right,
         *                         center or left.
         * @param {Array} [adjust] An array of numbers to adjust the positioning [0: adjust x, 1:
         *                         adjust y].
         *
         * @method contextOrientation
         * @member jQuery
         *
         * @since 6.11.0
         */
        contextOrientation: function (context, orient, adjust) {
            var self, adjustOrientation;

            self = this;
            adjust = adjust || [0, 0];

            adjustOrientation = function (orient, triedAlignments) {
                var contextO, contextW, contextH, orientX, orientY, elem, elemW, elemH, pos;

                // If triedAlignments is not defined, we assume that we tried no alignemtns so far.
                triedAlignments = triedAlignments || {
                    top: false,
                    right: false,
                    bottom: false,
                    left: false
                };

                if (context instanceof $.Event) {
                    contextO = { left: context.pageX, top: context.pageY };
                    contextW = 0;
                    contextH = 0;
                } else {
                    context = $(context);
                    contextO = context.offset();
                    contextW = context.outerWidth();
                    contextH = context.outerHeight();
                }

                orientX = xExpr.exec(orient);
                orientY = yExpr.exec(orient);

                orientX = orientX ? orientX[1] : '';
                orientY = orientY ? orientY[1] : '';

                elem = $(self);

                // We reset the position of the element so it can expand its width. An element which
                // is located on the far right may get a reduced outer width, because the browser
                // tries to render it within the viewport.
                elem.css({
                    top: 0,
                    left: 0,
                    position: 'absolute'
                });

                elemW = elem.outerWidth();
                elemH = elem.outerHeight();
                pos = contextO;

                switch (orientX) {
                case 'right':
                    pos.left += contextW + adjust[0];
                    break;
                case 'left':
                    pos.left -= elemW + adjust[0];
                    break;
                case 'center':
                    pos.left += (contextW / 2) - (elemW / 2) + adjust[0];
                    break;
                default:
                    pos.left += adjust[0];
                    break;
                }

                switch (orientY) {
                case 'bottom':
                    pos.top += contextH + adjust[1];
                    break;
                case 'top':
                    pos.top -= elemH + adjust[1];
                    break;
                case 'middle':
                    pos.top += (contextH / 2) - (elemH / 2) + adjust[1];
                    break;
                default:
                    pos.top += adjust[1];
                    break;
                }

                elem.css({
                    'position': 'absolute',
                    'top': pos.top,
                    'left': pos.left
                });
            };

            return self.each(function () {
                adjustOrientation(orient);
            });
        }
    });

    return ep;

});