/**
 * FontEffect - jQuery plugin for font effect
 *
 * @author Alessandro Uliana (fonteffect@iofo.it)
 *
 * Copyright (c) 2009 Alessandro Uliana
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 * Demo and examples on
 * http://www.iofo.it/jquery/fonteffect/
 *
 * @requires jQuery v1.3.2
 *
 * @version:  1.1.1 - 12/9/2009
 *  fixed text-align problems
 *  fixed example.htm file
 *  code cleaned
 * @version:  1.1.0 - 26/8/2009
 *  reduced size and execution time
 *  fixed default values and handling
 *  fixed an error with italic fonts
 *  fixed mirror height when different detail value
 *  added chaining to methods
 *  fixed inline/block problems
 *  added options:
 *     css
 *     preset
 *     fxcolor
 *     printEffect
 *     mirrorAutomargin
 *  added functions:
 *     changetextFE(newtext):
 *
 * @previous version: 1.0.0 - 30/3/2009
 */
(function($){
    //* Global Variables *************************************************************
    var FE={};
    //* Tabella posizioni layer *************************************************************
    FE.tabpos = ["", "0001021020212212", "00010203041020304041424344142434", "000102030405061020304050606162636465162636465666"];
    FE.plugindefault = {
        css                 :false,
        fxcolor             :false,
        outline             :false,
        outlineColor        :false,
        outlineColor1       :false,
        outlineColor2       :false,
        outlineWeight       :1,    // 1=light, 2=medium, 3=bold
        mirror              :false,
        mirrorColor         :false,
        mirrorOffset        :-10,
        mirrorHeight        :70,
        mirrorDetail        :1,
        mirrorTLength       :50,
        mirrorTStart        :0.2,
        mirrorAutomargin    :true,
        shadow              :false,
        shadowColor         :false,
        shadowOffsetTop     :2,
        shadowOffsetLeft    :false,
        shadowWeight        :1,
        shadowOpacity       :0.5,
        gradient            :false,
        gradientColor       :false,
        gradientPosition    :20,
        gradientLength      :50,
        gradientSteps       :20,
        hideText            :false,
        preset              :false,
        printEffect         :false,
        test                :false
        };
    //* Main Function *******************************************************************************
    $.fn.FontEffect = function(o){
        //* Extend Defaults *********************************************************************
        var d = $.extend( {} , FE.plugindefault , ( (o.preset) ? ( typeof(o.preset)=="string" ) ? eval(o.preset) : o.preset : o ) );
        //* Main Loop ********************************************************************
        this.not(".JQFE").each(function(){
            //* Check and correct options ********************************************************************
            // set outline as default
            if(!d.outline &&
                !d.shadow  &&
                !d.mirror  &&
                !d.gradient) {d.outline=true;}
            // find (sort of) contrasting color
            if(!d.fxcolor){d.fxcolor=pickcontrast($(this).css("color"));}
            // set the deault colors (contrasting for all but mirror)
            if(d.outline){
                if(!d.outlineColor && !d.outlineColor1 && !d.outlineColor2){
                    d.outlineColor=d.fxcolor;
                    }
                if(!d.outlineColor1) { d.outlineColor1=d.outlineColor  || d.outlineColor2;}
                if(!d.outlineColor2) { d.outlineColor2=d.outlineColor1 || d.outlineColor ;}
                if(d.outlineWeight > 3 || d.outlineWeight < 1) { d.outlineWeight = 1 ;}
                if(d.outlineWeight == "Light")  {d.outlineWeight = 1;}
                if(d.outlineWeight == "Medium") {d.outlineWeight = 2;}
                if(d.outlineWeight == "Bold")   {d.outlineWeight = 3;}
                }
            if(d.shadow){
                if(!d.shadowColor) {d.shadowColor=d.fxcolor;}
                if(d.shadowBlur) {d.shadowWeight=d.shadowBlur;}
                if(d.shadowWeight == "Light" )  {d.shadowWeight = 0;}
                if(d.shadowWeight == "Normal")  {d.shadowWeight = 1;}
                if(d.shadowWeight == "Medium" ) {d.shadowWeight = 2;}
                if(d.shadowWeight == "High" )   {d.shadowWeight = 3;}
                }
            if(d.gradient && !d.gradientColor)    {d.gradientColor=d.fxcolor;}
            if(d.mirror){
                if(!d.mirrorColor)      {d.mirrorColor= d.fxcolor || d.css.color || $(this).css("color");}
                if(d.mirrorDetail > 3 || d.mirrorDetail < 1) {d.mirrorDetail = 1;}
                if(d.mirrorDetail == "High" ) {d.mirrorDetail = 1;}
                if(d.mirrorDetail == "Medium" ) {d.mirrorDetail = 2;}
                if(d.mirrorDetail == "Rippled" ) {d.mirrorDetail = 3;}
                }
            if(d.shadow   && !d.shadowOffsetLeft) {d.shadowOffsetLeft=d.shadowOffsetTop;}
            if(d.shadow   && d.shadowBlur && !d.shadowWeight) {d.shadowWeight=d.shadowBlur;}

            //* get the element display option and change to inline ********************************************************************
            var userdisplay=$(this).css("display");
            var userposition=$(this).css("position");
            //* get the element text-align value change to "left" ********************************************************************
            var usertextalign= $(this).css("textAlign");
            $(this).css("textAlign","left");
            //* change the display and position values to get the exact element dimensions
            var css={
                display: "inline",
                position:((userposition != "absolute")?"relative":"absolute")
                };
            //* add the .css option values ********************************************************************
            if(d.css) {$.extend(css,d.css);}
            //* assign new CSS ********************************************************************
            $(this).css(css);
            //* Local Variables ********************************************************************
            var h=$(this).height();
            var H=h+"px";
            var w=$(this).width()*(($(this).css("font-style")=="italic")?1.1:1.04);
            var W=w+"px";
            var t=$(this).html();
            //* Set Class, Options and CSS for the main element ********************************************************
            $(this)
                .data("options", d)
                .addClass("JQFE")
                .css({
                    width: W,
                    height: H,
                    display: userdisplay,
                    zoom: 1
                    });
            //* correct the user's text-align:right with float:right (and add a clear tag)
            if(usertextalign=="right"){
                $(this)
                    .css({float:"right"})
                    .after(
                        $("<div>").css({
                            content:".",
                            display:"block",
                            clear:"both",
                            visibility:"hidden",
                            lineHeight:"0",
                            height:"0"
                            })
                        )
            }
            //* correct the user's text-align:center with margin:auto
            if(usertextalign=="center"){
                $(this).css({marginLeft:"auto",marginRight:"auto"})
            }
            //* Create the MyContainer structure ***********************************************
            var MyContainer=$("<div>").css({ // need extra div for IE zindex bug
                display: userdisplay,
                width: W,
                height: H,
                position: "relative"
            });
            //* MyContainer For the central layer ***********************************************
            MyContainer.append(
                $("<div>")
                    .html(t)
                    .addClass('JQFEText')
                    .css({
                        display:  d.hideText ? "none" :  userdisplay,
                        width: W,
                        height: H,
                        position: "relative",
                        zIndex:   100
                    })
            );
            //* MyContainer For the Upper Effect layer ***********************************************
            var alldivsup=$("<div>").css({
                display: userdisplay,
                width: W,
                height: H,
                left: "0px",
                position: "absolute",
                top:      0+"px",
                //top:      parseInt($(this).css("paddingTop"),10)+"px",
                zIndex:   110
            }).addClass((!d.printEffect)?"do_not_print_this_FE":"");
            //* MyContainer For the Lower Effect layer ***********************************************
            var alldivsdown=$(alldivsup).clone().css({zIndex: 90});
            $(this).html("");
            //* Mirror Effect ****************************************************************
            if(d.mirror){
                d.mirrorHeight /= d.mirrorDetail;
                var mirrormargin=0;
                for(var iM=0;iM<h*(d.mirrorHeight/100);iM++){
                    var cssM_top1    =(h+d.mirrorOffset+iM*d.mirrorDetail)-((d.hideText)?h:0)+"px";
                    var cssM_height  =d.mirrorDetail+"px";
                    var cssM_top2    =((h*-1)+iM*(100/d.mirrorHeight))+"px";
                    var cssM_opacity=d.mirrorTStart-(iM*(d.mirrorTStart/((d.mirrorHeight/100)*d.mirrorTLength)));
                    var appoM=$("<div>")
                        .addClass("JQFEMirror")
                        .css({
                            position: "absolute",
                            top:      cssM_top1,
                            height:   cssM_height,
                            width:    W,
                            overflow: "hidden"
                        })
                        .append(
                            $("<div>")
                            .html(t)
                            .css({
                                position: "absolute",
                                color:    d.mirrorColor,
                                top:      cssM_top2,
                                width:    W,
                                opacity:  cssM_opacity
                            })
                        );
                    mirrormargin+=d.mirrorDetail;
                    // Skip Non Visible Layers ************************************************
                    if(cssM_opacity<0.01) { break; }
                    alldivsdown.append(appoM);
                }
                if(d.mirrorAutomargin) {$(this).css("margin-bottom",mirrormargin+"px");}
            }
            //* Outline Effect ***************************************************************
            if(d.outline){
                var totdivO =(d.outlineWeight)*8;
                var to=FE.tabpos[d.outlineWeight];
                for(var iO=0;iO<totdivO;iO++){
                    var appoO=$("<div>")
                        .addClass("JQFEOutline")
                        .html(t)
                        .css({
                            position: "absolute",
                            top:     (to.charAt(iO*2)  -d.outlineWeight)+"px",
                            left:    (to.charAt(iO*2+1)-d.outlineWeight)+"px",
                            width:    W,
                            color:   ((iO<totdivO/2+d.outlineWeight)?d.outlineColor1: d.outlineColor2),
                            zIndex:  ((iO>totdivO-totdivO/3)?20: 30)
                        });
                    alldivsdown.append(appoO);
                }
            }
            //* Shadow Effect ****************************************************************
            if(d.shadow){
                var totdivS = (d.shadowWeight)*8 || 1;
                var tos=FE.tabpos[d.shadowWeight];
                for(var iS=0;iS<totdivS;iS++){
                    var appoS=$("<div>")
                        .addClass("JQFEShadow")
                        .html(t)
                        .css({
                            opacity:  d.shadowOpacity,
                            position: "absolute",
                            top:     (tos.charAt(iS*2)  -d.shadowWeight)+d.shadowOffsetTop +"px",
                            left:    (tos.charAt(iS*2+1)-d.shadowWeight)+d.shadowOffsetLeft+"px",
                            width:    W,
                            height:   H,
                            color:    d.shadowColor,
                            zIndex:   10
                        });
                    alldivsdown.append(appoS);
                }
            }
            //* Gradient Effect *************************************************************
            if(d.gradient){
                var step    = Math.round((h*(d.gradientLength*0.01))/d.gradientSteps);
                var postop  = Math.round(h*(d.gradientPosition*0.01));
                var opa     =(1/d.gradientSteps);
                var gcolor  = d.gradientColor;
                for(var iG=0;iG<d.gradientSteps;iG++){
                    var cssG_top1   = (((iG === 0)?0: postop)+iG*step)+"px";
                    var cssG_height = (((iG === 0)?postop: 0)+step  )+"px";
                    var cssG_top2   = ((((iG === 0)?0: postop)+iG*step)*-1)+"px";
                    var appoG=$("<div>")
                        .addClass("JQFEGradient")
                        .css({
                            position: "absolute",
                            top:      cssG_top1,
                            height:   cssG_height,
                            left:     "0px",
                            width:    W,
                            overflow: "hidden"
                        })
                        .append(
                        $("<div>")
                            .html(t)
                            .css({
                                width:    "100%",
                                position: "absolute",
                                top:      cssG_top2,
                                color:    gcolor,
                                opacity:  1-opa*iG
                            })
                        );
                    alldivsup.append(appoG);
                }
            }
            //* End Effects ******************************************************************
            //* Draw Effects ******************************************************************
            MyContainer.append(alldivsdown);
            MyContainer.append(alldivsup);
            $(this).append(MyContainer);


        });//* Main Loop End *******************************************************************************
        //* Internal Functions ******************************************************************************
        function hex2rgb(hexcolor){
            hexcolor=hexcolor.substring(1);
            if(hexcolor.length == 3) { hexcolor=hexcolor.charAt(0)+hexcolor.charAt(0)+hexcolor.charAt(1)+hexcolor.charAt(1)+hexcolor.charAt(2)+hexcolor.charAt(2);}
            var rgbcolor="rgb("+parseInt(hexcolor.substring(0, 2), 16)+", "+parseInt(hexcolor.substring(2, 4), 16)+", "+parseInt(hexcolor.substring(4, 6), 16)+")";
            return(rgbcolor);
        }
        function chkColorString(col){
            // test if "col" is a valid html color definition string (rgb(n, n, n) or #fff or #ffffff)
            return(/(#([0-9A-Fa-f]{3,6})\b)|(rgb\(\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*,\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*,\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*\))|(rgb\(\s*(\d?\d%|100%)+\s*,\s*(\d?\d%|100%)+\s*,\s*(\d?\d%|100%)+\s*\))/.test(col));
        }
        function pickcontrast(col){
            if(chkColorString(col)){
                col = col.toUpperCase();
                if(col.charAt(0) == "#") {col=hex2rgb(col);}
                var appoPC=col.substring(4, col.length-1).split(", ");
                var g=255-parseInt(appoPC[0],10);
                var b=255-parseInt(appoPC[1],10);
                var r=255-parseInt(appoPC[2],10);
                col="rgb("+r+", "+g+", "+b+")";
            }
        return(col);
        }
        //* Add no print CSS to header *******************************************************************************
        $("head").append($("<style type='text/css' media='print'>.do_not_print_this_FE{visibility:hidden;}</style>"));
        //* Chain *******************************************************************************
        return this;
    }; //* Main Function End *******************************************************************************
    //* External Functions *******************************************************************************
    $.fn.changeOptionsFE = function(newoptions){
        if(this){
            var oldoptions=$(this).data("options") || {};
            $.extend(oldoptions, newoptions);
            $(this).data("options", oldoptions);
        }
        return this;
    };
    $.fn.redrawFE = function(newoptions){
        if(this && $(this).hasClass("JQFE")){
            if(newoptions) {$(this).changeOptionsFE(newoptions);}
            $(this).removeFE();
            $(this).removeClass("JQFE");
            $(this).FontEffect($(this).data("options"));
        }
        return this;
    };
    $.fn.removeFE = function(removeoptions){
        if(this && $(this).hasClass("JQFE")){
            var t=$(this).find("div[class='JQFEText']").html()+"";
            if(t=="null") { t=$(this).html(); }
            if(removeoptions) {
                $(this).data("options", {});
                $(this).removeClass("JQFE");
                }
            $(this).find("div[class^='JQFE']").remove();
            $(this).html(t);
        }
        return this;
    };
    $.fn.changetextFE = function(newtext,newwidth){
        if(this && newtext){
            $(this).find("div[class*=JQFE]").html(newtext);
            if(newwidth) {
                $(this).find("div[class*=JQFE]").css("width",newwidth+"px");
            }
        }
        return this;
    };
    //* External Functions End *******************************************************************************
})(jQuery);
//* End FontEffect Plugin ******************************************************************************

