/* Dart legacy support for sites without cn-fe-ads site mods completed */

/**
 * @class        CN Dart Object
 * @description  Contains methods to build and update Dart ad calls
 * @public
 * @author       Paul Bronshteyn
 */
CN.dart = (function() {
    var
        /**
         * To save some time per call, we only want (and need) to run the main body
         * of CN.dart.init(object) one time.  This shall be it's flag.
         */
        initialized=false,

        /**
         * Url to loocal dart html page which loads within the frame
         * @memberOf    CN.dart
         * @private
         * @type        string
         * @default     /ads/displayad.html
         */
        frameUrl = '/ads/displayad.html',

        /**
         * DoubleClick server url
         * @memberOf    CN.dart
         * @private
         * @type        string
         * @default     http://ad.doubleclick.net/adj/
         */
        dcUrl = 'http://ad.doubleclick.net/adj/',

        /**
         * Placeholder for modified DoubleClick site.
         * Remains empty unless set using API interface CN.dart.setSite()
         * @memberOf    CN.dart
         * @private
         * @type        string
         */
        modSite,

        /**
         * DoubleClick site
         * Implemented with a mini-sniffer for some User-Agent detection.
         * @memberOf    CN.dart
         * @param {string} ua User-Agent string
         * @private
         * @type        string
         * @default     .dart
         */
        dcSite = (function(ua){
            var suff='dart',
                setMod=false;

            //If browser is iPad based, use the iPad specific dart string.
            if (ua.indexOf('ipad')!==-1){
                    suff +='.ipad',
                    /*  VERY important.  This ensures that once the site is modded, even
                        values set through the CN.dart.init call will be forced to use this
                        dart suffix.
                    */
                    setMod=true;
            }
            //Check if dartOverride is being used, and give that higher precedence.
            suff = (CN.site.testads ? '.' + CN.site.testads : '.' + suff);
            if (setMod) { modSite=suff;}
            return suff;
        })
        (navigator.userAgent.toLowerCase()),

        /**
         * Section of the site
         * @memberOf    CN.dart
         * @private
         * @type        string
         * @default     /{section} || /home
         */
        zone = '/' + (CN.site.testads || CN.url.section().replace(/-/g, '_') || 'home') + ';',

        /**
         * Placeholder for modified DoubleClick site.
         * Remains empty unless set using API interface CN.dart.setSite()
         * @memberOf    CN.dart
         * @private
         * @type        string
         */
        modZone,

        /**
         * A unique identifier for the page required by DoubleClick to be
           sent with every ad call
         * @memberOf    CN.dart
         * @private
         * @type        integer
         */
        ord = Math.random() * 10000000000000000,

        /**
         * Index of the advertising placement on the page
         * @memberOf    CN.dart
         * @private
         * @type        integer
         */
        tile = 0,

        /**
         * Array of ad has values sorted by tile
         * @memberOf    CN.dart
         * @private
         * @type        array
         */
        tiles = [],

        /**
         * Ad placement collection
         * @memberOf    CN.dart
         * @private
         * @type        object
         */
        ads = {},

        /**
         * A boolean value to determine if a ad request needs to be paused
         * default value is false
         * @memberOf    CN.dart
         * @private
         * @type        boolean
         */
        pause = false,

        /**
         * Construct the ad request url
         * @param   {string}    placement   Dart ad placement name
         * @param   {object}    params      Dart ad params
         * @memberOf    CN.dart
         * @private
         */
        buildurl = function(placement,params){
            return frameUrl + '?req=' + dcUrl + CN.dart.getSite() + CN.dart.getZone() + (params || ads[placement].getParams()) + 'tile=' + ads[placement].tile+ ';'
        },

        /**
         * Reg-ex for testing valid dartsite patterns.
         * Used mainly by siteSuff to esure external api calls to CN.dart.setSite(str)
         * maintain the suffix portion of the site.
         * @private
         */

        sitePat=new RegExp("\\.(?:dart"+(CN.site.testads? "|" + CN.site.testads : "")+").*|$"),

        /**
         * DoubleClick site suffix preserver
         * In the case that we are using an alternate suffix (other than .dart)
         * this helper function will help preserve the custom suffix when the
         * setSite api is used to modify the dcSite.
         * @memberOf    CN.dart
         * @private
         * @type        string
         */
        siteSuff = function(Site){
            return Site.replace(sitePat,CN.dart.getSite().match(sitePat)[0])
        },

        /**
         * On draw event announcer.  Runs when an ad frame is loaded or reloaded.
         * @memberOf    CN.dart
         * @private
         */
        ondraw = function(placement,ad){
            jQuery(window).trigger('CN.customEvents.dartAdDrawn',[placement,"#"+placement, ad]);
        },

        /**
         * Instantiable Class for dart ad storace
         * @param   {string}    placement   Dart ad placement name
         * @param   {object}    options     Options set on init
         * @param   {number}    tile        Unique sequence for ad
         * @param   {boolean}   [store]     Store ad placement?
         * @memberOf    CN.dart
         * @private
         */
        Ad=function (placement,options,tile,store){
                this.width=jQuery('#' + placement).width(),
                this.funcs={},
                this.options=options,
                this.tile=tile;
                this.store=store === true;
        };

        /**
         * Ad class prototype to allow dynamic param complilation
         * @memberOf    CN.dart
         * @private
         */

         Ad.prototype={
            sz : '',
            kws : '',
            dcopt : '',

            getParams : function(){
            return this.kws + this.sz + this.dcopt;
            },

            setParams : function(x){
                var kws=x.match(/(?:(?:kw|!c)=[^;]*;)+/),
                    sz=x.match(/(?:sz=[^;]+;)+/),
                    dcopt=x.match(/(?:dcopt=[^;]+;)+/);
                this.kws = kws ? kws[0] : this.kws;
                this.sz = sz ? sz[0] : this.sz;
                this.dcopt = dcopt ? dcopt[0] : this.dcopt;
            },

            getTiles : function(){
                return CN.dart.getTiles();
            }

         };
    /**
     * @scope CN.dart
     */
    return {

        /**
         * Initialize dart parameters (site, zone, etc)
         * These will replace the default (dcSite, dZone) values above,
         * and is intended to be used ONLY for initilizing dart.
         * Please use the setZone and setSite interfaces for additional modifications.
         * @param   {string}    placement Dart ad placement name
         */
        init : function(defaults) {
            if (initialized) {
                return this;
            }
            if(defaults.site){
                dcSite = ( modSite ? siteSuff(defaults.site) : defaults.site);
            }

            dcSite = dcSite.charAt(0)==='.' ? CN.site.name + dcSite : dcSite;
            if(modSite) {
                modSite=dcSite;
            }
            zone = defaults.zone || zone;
            dcUrl = defaults.url || dcUrl;
            initialized = true;
            return this;
        },

        /**
         * get ad placement
         * @param   {string}    placement Dart ad placement name
         */
        calls : function(placement) {
            return (placement===true ? ads : ads[placement] || {});
        },

        /**
         * set dart calls state to paused [true:paused] [false:active]
         * @param   {string}    placement Dart ad placement name
         */
        setPause : function(status) {
            pause = status;
            return this;
        },

        /**
         * get dart call state
         * @param   {string}    placement Dart ad placement name
         */
        getPause : function() {
            return pause;
        },

        /**
         * get the site
         */
        getSite : function() {
            return (modSite ? modSite : dcSite);
        },

        /**
         * get ad placement
         * @param   {string}    placement Dart ad placement name
         */
        setSite : function(Site) {
            if(!CN.site.testads){
                modSite=siteSuff(Site);
            }
            return this;
        },

        /**
         * get the tiles array
         */
        getTiles : function(){
            return tiles;
        },

        /**
         * get the zone
         */
        getZone : function() {
            return modZone ? modZone : zone;
        },

        /**
         * get ad placement
         * @param   {string}    placement Dart ad placement name
         */
        setZone : function(Zone) {
            if(!CN.site.testads){
                modZone=Zone;
            }
            return this;
        },

        /**
         * On draw event announcer.  Runs when an ad frame is loaded or reloaded.
         * @memberOf    CN.dart
         */

        onDraw : function (placement,ad) {
            ondraw(placement,ad);
        },

        /**
         * Update params for all placements on the page or for just [placement]
         * @param   {string}    params
         * @param   {string}    placement Dart ad placement name
         */
        update : function(params,placement) {
            if (params && placement && placement in ads){
                ads[placement].setParams(params);
                return true;
            }
            if (params){
                for (var ad in ads) {
                    ads[ad].setParams(params);
                }
            } else {
                return false;
            }
            return true;
        },

        /**
         * Clone a current ad as "placement" and make a request
         * Used for making very simple requests.
         * @param   {string}    sz Dart ad placement identifier
         * @param   {string}    name Dart ad placement name
         */
        clone : function(sz,name) {
            if(tile===0){
                return this;
            }
            var ad = ads[tiles[0]],
                placement=name+sz,
                cln = new Ad(placement, ad.options, 0, true);
            return cln.setParams(ad.getParams()),
                cln.setParams('sz=' + sz + ';'),
                CN.dart.drawFrame(sz,name).request(placement,cln.getParams(),cln.options);
        },

        /**
         * Generate an iframe for the ad, and append to the cintainer [placement]_frame
         * @param   {string}    sz Dart ad placement identifier
         * @param   {string}    name Dart ad placement name
         */
        drawFrame : function(sz,name) {
            var dims=sz.split('x'),
                placement=name+sz;
            jQuery('<iframe/>').attr({
                id : placement,
                name : placement,
                src : '#',
                height : dims[1],
                width : dims[0],
                frameBorder : 0,
                scrolling : 'no'
            }).appendTo('#' + placement + '_frame');
            return this;
        },

        /**
         * Request ad placement
         * @param   {string}    placement   Dart ad placement name
         * @param   {object}    params      Dart ad params
         * @param   {boolean}   [store]     Store ad placement?
         * @param   {object}    [funcs]     Callbefore and/or callback obj
         * @uses                            CN.frame.refresh
         */
         request : function(placement, params, options) { // options is boolean (store), or object with store (probably) and callbacks (maybe)

            if (CN.site.noads) {
                return this;
            }

            var store = CN.isBoolean(options) ? options : options.store === true;

            //Add the current placement value to the tiles array to preserve order
            tiles[tile] = placement;
            ads[placement] = new Ad(placement, options, ++tile, store);
            ads[placement].setParams(params);
            ads[placement].url = buildurl(placement);

            options.funcs=CN.callwhen.add("after",{
                    func:CN.dart.onDraw,
                    params:[placement,ads[placement]]
                    }, options.funcs || {});

            ads[placement].funcs = options.funcs;

            jQuery(window).triggerHandler('CN.customEvents.dartNewAd',[placement,pause]);

            if (!pause) {
               ads[placement].modifiedurl = buildurl(placement);
               CN.frame.refresh('#' + placement, ads[placement].modifiedurl + 'ord=' + ord, ads[placement].funcs);
            }

            CN.debug.info('CN Dart Request', [placement, ads[placement], ord]);
            return this;
        },

        /**
         * Refresh ad placement(s).
         * @description This will refresh all ad placements provided to the function or all the
                        placements currently on the page.
         * @param       {string,array}  [placement]     Placement or Placements to refresh
                        (string)                        Customized dart url to overrride the default
         * @uses                                        CN.frame.refresh
         */
        refresh : function(placement,params) {
            var p = (CN.isString(placement)) ? placement.split(/,|\s+/) : (jQuery.isArray(placement)) ? placement : ads;
            ord = Math.random() * 10000000000000000;

            // the next line removes any references to a doubleclick frame busting ads
            if (!p.length) {
                CN.debug.info("Ads Cleaning:",[jQuery('script[id*="prscr"], .prWrap').length]);
                jQuery('script[id*="prscr"]').remove();
            }

            // refresh frames
            jQuery.each(p, function(i, v) {
                var ad = (CN.isNumber(i)) ? v : i;
                if (ad in ads) {
                    if(ads[ad].store){
                    // reset the width, frame busting ads set it to 0px
                    jQuery('#' + ad).width(ads[ad].width).parent().find(".prWrap").remove();
                    ads[ad].modifiedurl = buildurl(ad,params);
                    CN.frame.refresh('#' + ad, ads[ad].modifiedurl + 'ord=' + ord,ads[ad].funcs);
                }
                }
            });
            return this;
        }
    };
})();


