/* -------------------------------------------- 
* Tweetmix Simple Widget Script*
* Created by @Ventus80*
* copyright (c) userstorylab * 
* Thank by Dustin Diaz (dustin@twitter.com)
* If you need help http://twitter.com/javascripts/widgets/widget.js
-----------------------------------------------*/

TMXW=window.TMXW||{};

/**
  * add core functionality to JS
  * Sugar Arrays http://www.dustindiaz.com/basement/sugar-arrays.html
  */
 
if (!Array.forEach) {

  Array.prototype.filter = function(fn, thisObj) {
    var scope = thisObj || window;
    var a = [];
    for (var i=0, j=this.length; i < j; ++i) {
      if (!fn.call(scope, this[i], i, this)) {
        continue;
      }
      a.push(this[i]);
    }
    return a;
  };

  //sorta like inArray if used clever-like
  Array.prototype.indexOf = function(el, start) {
    var start = start || 0;
    
    for (var i=0; i < this.length; ++i) {
      if (this[i] === el) {
        return i;
      }
    }

    return -1;
  };
}

/* first, a few dependencies */
(function() {
  if (TMXW && TMXW.Widget) {
    // this is most likely to happen when people try to embed multiple
    // widgets on the same page and include this script again
    return;
  }

  /**
    * Basic Array methods
    */
   
    function each(a, fn, opt_scope) {
        for (var i=0, j=a.length; i < j; ++i) {
            fn.call(opt_scope || window, a[i], i, a);
        }
    }
  
    function escap(str){
        var return_value = encodeURIComponent(str);
        return_value = return_value.replace(/\'/g, '\\\'');
        return_value = return_value.replace(/\"/g, '\\\"');

        return return_value;
    }
    
    var tweetmix_net = "http://tweetmix.net";
    
    function widget_tweets(contents){
        var url = tweetmix_net+"/widget/auth/retweet/";

        //url = url + "?msg=" + encodeURIComponent(contents);
        url = url + "?msg=" + contents;
        url = url + "&status_id=0";

        var status = "width=660,";
        status = status + "height=400,";
        status = status + "location=no,";
        status = status + "directories=no,";
        status = status + "menubar=no,";
        status = status + "status=no,";
        status = status + "toolbar=no, scrollbars=no, menubar=no,";
        status = status + "resizable=no";

         window.open(url, "tweetmix_tweets", status);
         //alert(contents);
    }
    
    function widget_retweet(screen_name, contents){
        var url = tweetmix_net+"/widget/auth/retweet/";

        //url = url + "?msg=" + encodeURIComponent(("RT @"+screen_name+" "+ contents));
        url = url + "?msg=" + "RT @"+screen_name+' '+ contents;
        url = url + "&status_id=0";

        var status = "width=660,";
        status = status + "height=400,";
        status = status + "location=no,";
        status = status + "directories=no,";
        status = status + "menubar=no,";
        status = status + "status=no,";
        status = status + "toolbar=no, scrollbars=no, menubar=no,";
        status = status + "resizable=no";

         window.open(url, "tweetmix_retweet", status);
         //alert(contents);
    }

    function widget_reply(screen_name, tid_status){
        var url = tweetmix_net+"/widget/auth/reply/";

        url = url + "?msg=" + "@"+screen_name+' ';
        url = url + "&status_id="+tid_status;

        var status = "width=660,";
        status = status + "height=400,";
        status = status + "location=no,";
        status = status + "directories=no,";
        status = status + "menubar=no,";
        status = status + "status=no,";
        status = status + "toolbar=no, scrollbars=no, menubar=no,";
        status = status + "resizable=no";

        window.open(url, "tweetmix_reply", status);
        //alert("@"+screen_name +" / "+ tid_status)
    }

  /**
    * @constructor
    * Widget Base for new instances of the Twitter search widget
    * @param {Object} opts the configuration options for the widget
    */
  TMXW.Widget = function(opts) {
    this.init(opts);
  };

  (function() {
    //NOTE @Ventus80 : start
    // Internal Namespace.
    var tmx_widget = {};
    var isHttps = location.protocol.match(/https/);
    //var httpsImageRegex = /^.+\/profile_images/;
    //var httpsImageReplace = 'https://s3.amazonaws.com/twitter_production/profile_images';

    // cache object for searching duplicates
    var reClassNameCache = {};

    // reusable regex for searching classnames
    var getClassRegEx = function(c) {

      // check to see if regular expression already exists
      var re = reClassNameCache[c];

      if (!re) {
        re = new RegExp('(?:^|\\s+)' + c + '(?:\\s+|$)');
        reClassNameCache[c] = re;
      }

      return re;
    };

    var getByClass = function(c, tag, root, apply) {
      var tag = tag || '*';
      var root = root || document;

      var nodes = [],
          elements = root.getElementsByTagName(tag),
          re = getClassRegEx(c);

      for (var i = 0, len = elements.length; i < len; ++i) {
        if (re.test(elements[i].className)) {
          nodes[nodes.length] = elements[i];

          if (apply) {
            apply.call(elements[i], elements[i]);
          }

        }
      }

      return nodes;
    };
    
    var getByTag = function(el, tag) {
        return el.getElementsByTagName(tag)[0];
    };

    var browser = function() {
      var ua = navigator.userAgent;
      return {
        ie: ua.match(/MSIE\s([^;]*)/)
      };
    }();

    var byId = function(id) {
      if (typeof id == 'string') {
        return document.getElementById(id);
      }
      return id;
    };

    var trim = function(str) {
      return str.replace(/^\s+|\s+$/g, '')
    };

    var getViewportHeight = function() {
      var height = self.innerHeight; // Safari, Opera
      var mode = document.compatMode;
      if ((mode || browser.ie)) { // IE, Gecko
        height = (mode == 'CSS1Compat') ?
          document.documentElement.clientHeight : // Standards
          document.body.clientHeight; // Quirks
      }
      return height;
    };

    var insertAfter = function(el, reference) {
      reference.parentNode.insertBefore(el, reference.nextSibling);
    };

    var removeElement = function(el) {
      try {
        el.parentNode.removeChild(el);
      }
      catch (ex) { }
    };

    var getStyle = function() {
      if (document.defaultView && document.defaultView.getComputedStyle) {
        return function(el, property) {
          var value = null;
          var computed = document.defaultView.getComputedStyle(el, '');
          if (computed) {
            value = computed[property];
          }
          var ret = el.style[property] || value;
          return ret;
        };
      }
      else if (document.documentElement.currentStyle && browser.ie) { // IE method
        return function(el, property) {
          var value = el.currentStyle ? el.currentStyle[property] : null;
          return (el.style[property] || value);
        };
      }
    }();

    /**
      * classes object
      * - has - add - remove
      */
    var classes = {
        /*
      has: function(el, c) {
        return new RegExp("(^|\\s)" + c + "(\\s|$)").test(byId(el).className);
        return true;
      },
    */

      add: function(el, c) {
        if (!this.has(el, c)) {
          byId(el).className = trim(byId(el).className) + ' ' + c;
        }
      },

      remove: function(el, c) {
        if (this.has(el, c)) {
          byId(el).className = byId(el).className.replace(new RegExp("(^|\\s)" + c + "(\\s|$)", "g"), "");
        }
      }
    };

    /**
      * basic x-browser event listener util
      * eg: events.add(element, 'click', fn);
      */
    var events = {
      add: function(el, type, fn) {
        if (el.addEventListener) {
          el.addEventListener(type, fn, false);
        }
        else {
          el.attachEvent('on' + type, function() {
            fn.call(el, window.event);
          });
        }
      },
      remove: function(el, type, fn) {
        if (el.removeEventListener) {
          el.removeEventListener(type, fn, false);
        }
        else {
          el.detachEvent('on' + type, fn);
        }
      }
    };

    var hex_rgb = function() {

      function HexToR(h) {
        return parseInt((h).substring(0,2),16);
      }
      function HexToG(h) {
        return parseInt((h).substring(2,4),16);
      }
      function HexToB(h) {
        return parseInt((h).substring(4,6),16);
      }

      return function(hex) {
        return [HexToR(hex), HexToG(hex), HexToB(hex)];
      };

    }();

    /**
      * core type detection on javascript objects
      */
    var is = {
      bool: function(b) {
        return typeof b === 'boolean';
      },

      def: function(o) {
        return !(typeof o === 'undefined');
      },

      number: function(n) {
        return typeof n === 'number' && isFinite(n);
      },
      string: function(s) {
        return typeof s === 'string';
      },

      fn: function(f) {
        return typeof f === 'function';
      },

      array: function(a) {
        if (a) {
          return is.number(a.length) && is.fn(a.splice);
        }
        return false;
      }
    };

    var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];

    var absoluteTime = function(s) {
      var d = new Date(s);
      if (browser.ie) {
        d = Date.parse(s.replace(/( \+)/, ' UTC$1'));
      }
      var ampm = '';
      var hour = function() {
        var h = d.getHours();
        if (h > 0 && h < 13) {
          ampm = 'am';
          return h;
        }
        else if (h < 1) {
          ampm = 'am';
          return 12;
        }
        else {
          ampm = 'pm';
          return h - 12;
        }
      }();
      var minutes = d.getMinutes();
      var seconds = d.getSeconds();
      function getRest() {
        var today = new Date();
        if (today.getDate() != d.getDate() || today.getYear() != d.getYear() || today.getMonth() != d.getMonth()) {
          return ' - ' + months[d.getMonth()] + ' ' + d.getDate() + ', ' + d.getFullYear();
        }
        else {
          return '';
        }
      }
      return hour + ':' + minutes + ampm + getRest();
    };

    /**
      * relative time calculator
      * @param {string} twitter date string returned from Twitter API
      * @return {string} relative time like "2 minutes ago"
      */
    var timeAgo = function(dateString) {
      var rightNow = new Date();
      var then = new Date(dateString);

      if (browser.ie) {
        // IE can't parse these crazy Ruby dates
        then = Date.parse(dateString.replace(/( \+)/, ' UTC$1'));
      }

      var diff = rightNow - then;

      var second = 1000,
          minute = second * 60,
          hour = minute * 60,
          day = hour * 24,
          week = day * 7;

      if (isNaN(diff) || diff < 0) {
        return ""; // return blank string if unknown
      }

      if (diff < second * 2) {
        // within 2 seconds
        return "right now";
      }

      if (diff < minute) {
        return Math.floor(diff / second) + " seconds ago";
      }

      if (diff < minute * 2) {
        return "about 1 minute ago";
      }

      if (diff < hour) {
        return Math.floor(diff / minute) + " minutes ago";
      }

      if (diff < hour * 2) {
        return "about 1 hour ago";
      }

      if (diff < day) {
        return  Math.floor(diff / hour) + " hours ago";
      }

      if (diff > day && diff < day * 2) {
        return "yesterday";
      }

      if (diff < day * 365) {
        return Math.floor(diff / day) + " days ago";
      }

      else {
        return "over a year ago";
      }

    };

    /**
      * @constructor the classic twitter occasional job
      * @param {Function} job The job to execute upon each request
      * @param {Function} decay The deciding boolean method on whether to decay
      * @param {Int} interval The number in milliseconds to wait before executing
      */
    function Occasionally(job, decayFn, interval) {
      this.job = job;
      this.decayFn = decayFn;
      this.interval = interval;
      this.decayRate = 1;
      this.decayMultiplier = 1.25;
      this.maxDecayTime = 3 * 60 * 1000; // 3 minutes
    }

    Occasionally.prototype = {

      /**
        * @public
        * @return self
        * starts our occasional job
        */
      start: function() {
        this.stop().run();
        return this;
      },

      /**
        * @public
        * @return self
        * stops the occasional job
        */
      stop: function() {
        if (this.worker) {
          window.clearTimeout(this.worker);
        }
        return this;
      },

      /**
        * @private
        */
      run: function() {
        var that = this;
        this.job(function() {
          // running our decayer callback
          that.decayRate = that.decayFn() ? Math.max(1, that.decayRate / that.decayMultiplier)
                                          : that.decayRate * that.decayMultiplier;

          var expire = that.interval * that.decayRate;
          expire = (expire >= that.maxDecayTime) ? that.maxDecayTime : expire;
          expire = Math.floor(expire);

          that.worker = window.setTimeout(
            function () {
              that.run.call(that);
            },
            expire
          );

        });
      },

      /**
        * @public
        * @return self
        * stops occasional job and resets object
        */
      destroy: function() {
        this.stop();
        this.decayRate = 1;
        return this;
      }
    };

    /**
      * @Constructor runs a timer on an array passing back
      *              the next needle on each interval
      * @param haystack {Array}
      * @param time {Int} time in ms
      * @param loop {Bool} does this continue forever?
      * @param callback {Function} method that is passed back a needle for each interval
      */
    function IntervalJob(time, loop, callback) {
      this.time = time || 6000;
      this.loop = loop || false;
      this.repeated = 0;
      this.callback = callback;
      this.haystack = [];
    };

    IntervalJob.prototype = {

      set: function(haystack) {
        this.haystack = haystack;
      },

      add: function(needle) {
        this.haystack.unshift(needle);
      },

      /**
        * @public
        * @return self
        * begins the interval job
        */
      start: function() {
        if (this.timer) {
          return this;
        }
        this._job();
        var that = this;
        this.timer = setInterval(
          function() {
            that._job.call(that);
          }, this.time
        );

        return this;
      },

      /**
        * @public
        * @return self
        * stops the interval
        */
      stop: function() {
        if (this.timer) {
          window.clearInterval(this.timer);
          this.timer = null;
        }

        return this;
      },

      /**
        * @private
        */
      _next: function() {
        var old = this.haystack.shift();
        if (old && this.loop) {
          this.haystack.push(old);
        }
        return old || null;
      },

      /**
        * @private
        */
      _job: function() {
        var next = this._next();
        if (next) {
          this.callback(next);
        }

        return this;
      }

    };

    function Tweet(tweet, obj) {
     
      if (isHttps) {
        //tweet.avatar = tweet.avatar.replace(httpsImageRegex, httpsImageReplace);
      }
       
       //<div class="tmx_tweet" style="margin-left:0;">
       
       tweet.contents = (tweet.contents).replace(/<a/g, '<a style="color:#'+ obj.color_link+'"');
       tweet.source = (tweet.source).replace(/<a/g, '<a style="color:#'+ obj.color_text+'"');
       tweet.original_contents = escap(tweet.original_contents);
       
       var more_url = obj._base + "/?u=" + tweet.link_url;
       
       var avatar='<div class="tmx_tweet" style="margin-left:0;">';
       var orderTweet='';
       
       if(obj._widget_type == '0'){
           orderTweet='<li><a target="_blank" href="'+more_url+'" class="tmxwg_tweetinfo '+obj.btn_type_class+'" title="다른 트윗보기" style="color:#'+obj.color_text+'">다른 트윗보기</a></li>';
       }
       
       if(obj.is_show_avatar=='1'){
       
           avatar = '<div class="tmx_avatar">\
                            <a href="http://twitter.com/'+tweet.screen_name+'" target="_blank">\
                                <img src="'+tweet.photo_url+'" alt="'+tweet.screen_name+'" id="img'+tweet.id+'-'+tweet.tid_userid+'"/>\
                            </a>\
                        </div>\
                        <div class="tmx_tweet">';
       }
       
       var html = avatar + '<div class="tmx_author">\
                            <a style="color:#'+obj.color_link+'" href="http://twitter.com/'+tweet.screen_name+'" target="_blank">'+ tweet.screen_name +'</a>\
                        </div>\
                        <p class="tmx_article" style="color:#'+ obj.color_text+'">'+tweet.contents+'</p><div class="tmx_status">\
                        <span class="tmx_date" style="color:#'+ obj.color_text+'">\
                            <a style="color:#'+obj.color_text+'" href="http://twitter.com/'+tweet.screen_name+'/status/'+tweet.tid_status+'" target="_blank">'+tweet.date_tweeted+'</a>\
                        from ' + tweet.source+ '</span>\
                        <ul>'+orderTweet+
                            '<li><a href="#" class="tmx_btn_reply '+obj.btn_type_class+'" title="Reply" style="color:#'+obj.color_text+'">reply</a></li>\
                            <li><a href="#" class="tmx_btn_retweet '+obj.btn_type_class+'" title="Retweet" style="color:#'+obj.color_text+'">retweet</a></li>\
                        </ul>\
                        <div class="tmx_clear"></div>\
                    </div>';
        
      var div = document.createElement('div');

      div.id = 'tweet-id-' + ++Tweet._tweetCount;
      div.className = 'tmx_item';
      div.innerHTML = html;
      this.element = div;
    };
    
    function error_tweet(error_msg) {
      var html = '<li class="tmx_none_msg">'+error_msg+'</li>';
      var div = document.createElement('div');
      div.innerHTML = html;
      this.element = div;
    };

    // static count so all tweets (even on multiple inst widgets) will have unique ids
    Tweet._tweetCount = 0;

      tmx_widget.loadStyleSheet = function(url, widgetEl) {
        if (!TMXW.Widget.loadingStyleSheet) {
          TMXW.Widget.loadingStyleSheet = true;
          var linkElement = document.createElement('link');
          linkElement.href = url;
          linkElement.rel = 'stylesheet';
          linkElement.type = 'text/css';
          document.getElementsByTagName('head')[0].appendChild(linkElement);
          
          var timer = setInterval(function() {
            var style = getStyle(widgetEl, 'position');
            if (style == 'relative') {
              clearInterval(timer);
              timer = null;
              TMXW.Widget.hasLoadedStyleSheet = true;
            }
          }, 50);
        }
      };

    (function() {

      var isLoaded = false;
      tmx_widget.css = function(rules) {
        var styleElement = document.createElement('style');
        styleElement.type = 'text/css';
        if (browser.ie) {
          styleElement.styleSheet.cssText = rules;
        }
        else {
          var frag = document.createDocumentFragment();
          frag.appendChild(document.createTextNode(rules));
          styleElement.appendChild(frag);
        }
        function append() {
          document.getElementsByTagName('head')[0].appendChild(styleElement);
        }

        // oh IE we love you.
        // this is needed because you can't modify document body when page is loading
        if (!browser.ie || isLoaded) {
          append();
        }
        else {
          window.attachEvent('onload', function() {
            isLoaded = true;
            append();
          });
        }
      };
    })();


    TMXW.Widget.isLoaded = false;
    TMXW.Widget.loadingStyleSheet = false;
    TMXW.Widget.hasLoadedStyleSheet = false;
    TMXW.Widget.WIDGET_NUMBER = 0;
    
    TMXW.Widget.jsonP = function(url, callback) {
      var script = document.createElement('script');
      script.type = 'text/javascript';
      script.src = url;
      document.body.insertBefore(script, document.body.firstChild)
      callback(script);
      return script;
    };

    TMXW.Widget.prototype = function() {

      var http = isHttps ? 'https://' : 'http://';
      //var base = http + '192.168.1.211:99';
      var base = http + 'tweetmix.net';

      var occasionalInterval = 25000; // 20 seconds
      //var defaultAvatar = isHttps ? 'https://twitter-widgets.s3.amazonaws.com/j/1/default.gif' : 'http://widgets.twimg.com/j/1/default.gif';

      return {
        init: function(opts) {
          var that = this;
          //NOTE @Ventus80 : number
          // first, define public callback for this widget
          this._widgetNumber = ++TMXW.Widget.WIDGET_NUMBER;
          TMXW.Widget['receiveCallback_' + this._widgetNumber] = function(resp) {
            that._prePlay.call(that, resp);
          };          
          this._cb = 'TMXW.Widget.receiveCallback_' + this._widgetNumber;
          this.opts = opts;
          this._base = base;
          
          this._tweet_data_url = base + '/widget/getwidgetdata/';
          
          //NOTE @Ventus80 : widget type
          this._widget_type = opts.widget_type||'1';
          this._shape = opts.shape||'default';
          
          this._isRunning = false;
          this._hasOfficiallyStarted = false;
          this._hasNewSearchResults = false;
          this._rendered = false;

          this.timesRequested = 0;
          this.runOnce = false;
          this.newResults = false;
          this.results = [];
          this.jsonMaxRequestTimeOut = 19000;
          this.showedResults = [];
          
          //NOTE @Ventus80 : widget id
          this.id = opts.id || 'tmx-widget-' + this._widgetNumber;          
          this.target_url = opts.target_url;
          this.color_upper_back = opts.color_upper_back;
          this.color_upper_text = opts.color_upper_text;
          this.color_tweet_back = opts.color_tweet_back;
          this.color_text = opts.color_text;
          this.color_link = opts.color_link;
          this.color_border = opts.color_border;
          this.max_messages = opts.max_messages||'5';
          this.is_show_avatar = opts.is_show_avatar||'1';
          this.is_refresh_always = opts.is_refresh_always||'1';
          this.is_show_ads = opts.is_show_ads||'1';
          
          this.shape = opts.shape||'default';
          
          this.default_msg = (opts.default_msg)?document.title +' '+opts.default_msg:document.title;
          
          this.btn_type =  opts.btn_type||1;
          this.btn_type_class = (this.btn_type == 1)?'tmx_btn_both':'tmx_btn_icon';
          
          this.setDimensions(opts.width, opts.height);
          this.interval = opts.interval || 6000;
          this.title = opts.widget_title || '';
          this._setWidgetType(this._widget_type);
          this._setUrl();
          
          //최초 트윗 생성
          if (!opts.id) {
            document.write('<div class="tweetmix_widget_wrap" id="' + this.id + '"></div>');
          }
          //최초 위젯엘리먼트 메모리에 넣기
          this.widgetEl = byId(this.id);
          
          if (opts.id) {
            classes.add(this.widgetEl, 'tweetmix_widget_wrap');
          }

          //NOTE @Ventus80 : css add
          if (!TMXW.Widget.hasLoadedStyleSheet) {
            if (isHttps) {
            //NOTE @Ventus80 : not used
              //tmx_widget.loadStyleSheet('https://twitter-widgets.s3.amazonaws.com/j/2/widget.css', this.widgetEl);
              tmx_widget.loadStyleSheet('http://tweetmix.net/tmxWidget/style/tmixwdg.css', this.widgetEl);
              
            } else if (opts.creator) {
              tmx_widget.loadStyleSheet('/tmxWidget/style/tmixwdg.css', this.widgetEl);
            } else {
              //tmx_widget.loadStyleSheet('http://tweetmix.net/tmxWidget/style/tmixwdg.css', this.widgetEl);
              tmx_widget.loadStyleSheet(this._base + '/tmxWidget/style/tmixwdg.css', this.widgetEl);
              
            }
          }

          this.occasionalJob = new Occasionally(
            function(decay) {
              that.decay = decay;
              that._getResults.call(that);
            },

            function() {
              return that._decayDecider.call(that);
            },

            occasionalInterval
          );

          this._ready = is.fn(opts.ready) ? opts.ready : function() { };
          
          //NOTE @Ventus80 이게 무한 루프 값
          this._loop = false;
          this._isLive = false;
          this._showTopTweets = (this._isSearchWidget) ? true : false;
          this._behavior = 'default';
          
          return this;
        },

        /**
          * @public
          * @param {Int} w - width for widget
          * @param {Int} h - height for widget
          * @return self
          */
        //NOTE Ventus80 : w, h
        setDimensions: function(w, h) {
            
          if(this._widget_type=='1'){
              var default_w = 520;
              var default_h = 320;
          }else{
              var default_w = 230;
              var default_h = 460;
          }
          
          this.wh = (w && h) ? [w, h] : [default_w, default_h]; // default w/h if none provided
          
          if (w == 'auto' || w == '100%') {
            this.wh[0] = '100%';
          } else {
            this.box_w = ((this.wh[0] < 150) ? 150 - 2 : this.wh[0] - 2) + 'px';
            this.wh[0] = ((this.wh[0] < 150) ? 150 : this.wh[0]) + 'px'; // min width is 150
          }
          //tmxwg_hd padding 7px height 21px , tmxwg_ft padding 7px height 20px border 1px, tmxwg_box border 1px
          this.wh[1] = ((this.wh[1] < 100) ? 100 : this.wh[1]-73) + 'px'; // min height is 100
          return this;
        },

        /**
          * @private
          * @param {String} type the kind of widget you're instantiating
          * @return self
          */
        _setWidgetType: function(type) {
            this._isWidgetClass = 'tweetmix_widget_unit';
            this.tweetsMoreUrl = this._base +'?u='+this.target_url;
            
            switch(type) {
                case '0':
                  this._isWidgetClass = 'tweetmix_widget_unit';
                  this.tweetsMoreUrl = this.tweetsMoreUrl+ '/*';
                  break;
                case '1':
                  this._isWidgetClass =  'tweetmix_widget_post';             
                  break;
            };
            this._widget_type = type;            
            return this;
        },

        setBase: function(b) {
          this._base = b;
          return this;
        },
        
        _setUrl: function() {
            this.url = this._tweet_data_url +'?target_url=' + this.target_url +'&callback=' + this._cb +
                       '&max_messages=' + this.max_messages+'&type=' + this._widget_type;                   
          return this;
        },
        
        _setCratorUrl: function(url) {
            this.url = this._tweet_data_url +'?target_url=' + url +'&callback=' + this._cb +
                       '&max_messages=' + this.max_messages+'&type=' + this._widget_type;                   
          return this;
        },

        /**
          * @private
          */
        _getRGB: function(hex) {
          return hex_rgb(hex.substring(1, 7));
        },

        /**
          * @public
          * @param {string} classname
          * @param {string} tagname
          * @param optional {bool} whether to return collection or defaults to first match
          * @return HTML Element || Array HTML Elements
          * helper to get elements by classname based on the widget being the context
          */
        byClass: function(c, tag, opt_all) {
          var collection = getByClass(c, tag, byId(this.id));
          return (opt_all) ? collection : collection[0];
        },

        /**
          * @public
          * @return self
          * renders the widget onto an HTML page
          */
        render: function() {
          var that = this;
          
          if (!TMXW.Widget.hasLoadedStyleSheet) {
            window.setTimeout(function() {
              that.render.call(that);
            }, 50);
            return this;
          }
       
       //객체들 메모리에 저장 중요한 부분!!
          this.widgetEl.innerHTML = this._getWidgetHtml();          
          this.tmxHdEl = getByClass('tmxwg_hd','div',this.widgetEl)[0];
          this.tmxBdEl = getByClass('tmxwg_bd','div',this.widgetEl)[0];
          this.tmxFtEl = getByClass('tmxwg_ft','div',this.widgetEl)[0];
          
          this.tmxListEl = getByClass('tmx_list','div',this.widgetEl)[0];
          this.tmxAd = getByClass('tmx_ad','span',this.tmxFtEl)[0];
          
          //위젯 타입에 따른 헤드 버튼 관련
            if(this._widget_type=='1'){
                
                var tmxHdBtd_contnet = escap(this.target_url+' '+this.default_msg);
                
                this.tmxHdBtd = getByClass('tmx_btn_tweet','div',this.tmxHdEl)[0];
                var aBtn = getByTag(this.tmxHdBtd,'a');
                
                events.add(aBtn, 'click', function(){
                    widget_tweets(tmxHdBtd_contnet);
                });
            }
          
          this._rendered = true;
          // call the ready handler
          this._ready();
          return this;
        },

        /**
          * empty placeholder for removing events
          * on live widgets
          */
        removeEvents: function() { },
        /**
          * @private
          * @return {string}
          * builds an HTML string that represents the widget chrome
          */                
         
        _getWidgetHtml: function() {
          var that = this;

        function getHeader(obj) {
            
            var hd_html = '<h3><a target="_blank" style="color : #'+that.color_upper_text+';">' + that.title + '<span></span></a></h3>';
            
                if(obj._widget_type=='1'){

               hd_html += '<div class="tmx_btn_tweet">\
                                <a target="_blank" title="tweet" class="tmx_btn_both">\
                                <span style="color: #'+obj.color_upper_text+';">tweet</span></a></div>';
                
                }else{
                    hd_html += '<div class="tmx_btn_tweet"><a></a></div>';
                }
                
                hd_html += '<div class="tmx_clear"></div>';
                
              return hd_html;
        }
        
          var html = '<div class="'+this._isWidgetClass+'" style="width: ' + this.wh[0] + ';">\
            <div class="tmxwg_box" style="background-color: #'+that.color_tweet_back+'; border: 1px solid #'+that.color_border+'; width: '+this.box_w+';">\
                <div class="tmxwg_hd" style="background-color: #'+that.color_upper_back+';">' + getHeader(that) + ' \
                </div>\
                <div class="tmxwg_bd" style="height:'+this.wh[1]+'; overflow: auto;">\
                  <div class="tmx_list">\
                      <div class="tmx-reference-tweet"></div>\
                      <!-- tweets show here -->\
                  </div>\
                </div>\
                <div class="tmxwg_ft">\
                  <div class="tmx_more">\
                    <a target="_blank" href="'+that.tweetsMoreUrl+'" style="color:#'+that.color_text+';">\
                        <span></span>트윗 더보기 &rsaquo;\
                    </a>\
                  </div>\
                  <div class="tmx_copyright">\
                    <a target="_blank" href="'+this._base+'">Tweetmix</a>\
                  </div>\
                  <span class="tmx_ad" style="display: block"></span>\
                </div>\
            </div>\
          </div>';
          return html;
        },

        /**
          * @private
          * @return self
          * puts the tweet in the dom
          */
        _appendTweet: function(el, obj) {
          //this._insertNewResultsNumber();
          insertAfter(el, this.byClass('tmx-reference-tweet', 'div'));
          return this;
        },
        
        /**
          * @private
          * @return self
          * generates the HTML for a single tweet item
          */
        _createTweet: function(o) {
          //o.timestamp = o.created_at;
          //o.created_at = this._isRelativeTime ? timeAgo(o.created_at) : absoluteTime(o.created_at);
          this.tweet = new Tweet(o, this);
          if (this._isLive && this.runOnce) {
            this.tweet.element.style.opacity = 0;
            this.tweet.element.style.filter = 'alpha(opacity:0)';
            this.tweet.element.style.height = '0';
          }
          return this;
        },

        /**
          * @private
          * @param {Function} callback function that receives the results
          * makes a jsonP call to twitter.com
          */
        _getResults: function() {
          var that = this;          
          this.timesRequested++;
          this.jsonRequestRunning = true;

          this.jsonRequestTimer = window.setTimeout(function() {
              //alert(that.jsonRequestRunning);
              
            if (that.jsonRequestRunning) {
              clearTimeout(that.jsonRequestTimer);
              that.jsonRequestTimer = null;
            }

            that.jsonRequestRunning = false;
            removeElement(that.scriptElement);
            that.newResults = false;
            that.decay();
          }, this.jsonMaxRequestTimeOut);
          
          TMXW.Widget.jsonP(that.url, function(script) {
            that.scriptElement = script;
          });

        },

        /**
          * @public
          * @return self
          * clears out the tweet space. used internally,
          * but free to use publicly
          */
        clear: function() {
          var tweets = this.byClass('tmx_item', 'div', true);
          var results = this.byClass('twtr-new-results', 'div', true);
          tweets = tweets.concat(results);
          each(tweets, function(el) {
            removeElement(el);
          });

          return this;
        },

        _sortByMagic: function(results) {
            
           this._sortByLatest(results);

          return this;
        },

        _sortByLatest: function(results) {
          this.results = results;
          this.results.reverse();
          return this;
        },
        
        /**
          * @private
          * @method prePlay does a pre-check against last result.
          * @param resp the JSON response from twitter JsonP API
          */
        _prePlay: function(resp) {
          if (this.jsonRequestTimer) {
            clearTimeout(this.jsonRequestTimer);
            this.jsonRequestTimer = null;
          }

          if (!browser.ie) {
            removeElement(this.scriptElement);
          }
          
          if (resp.error) {
            this._error(resp.error_msg);
            this.newResults = false;
          }

          else if (resp.tweets && resp.tweets.length > 0) {
            this.response = resp;

            this.newResults = true;
            //this.sinceId = resp.max_id;
            //카운팅 관련 내용
            this.total_count =  resp.total_count;
            this.more_count =  this.total_count - this.max_messages;
            this.more_count =  this.more_count > 0 ? this.more_count : 0;
            
            this._sortByMagic(resp.tweets);
            
            if (this.isRunning()) {
              this._play();
              this._setAds(resp.widget_ads);
            }

          }
          else {
            this.newResults = false;
          }

          this._setUrl();
          if (this._isLive) {
            this.decay();
          }

        },
        
        _setAds: function(ads) {
            var that = this;
            each(ads, function(ad) {
                that.tmxAd.innerHTML += ad.contents;
            });
        },

        /**
          * @private
          * gets the ball rolling with a new widget
          * and resets the interval job
          */
        _play: function() {
          var that = this;
          if (this.runOnce) {
            this._hasNewSearchResults = true;
          }
      
          if (!this._isLive || this._behavior == 'all' || this._behavior == 'preloaded') {
              
            each(this.results, function(needle) {
                
              that._createTweet({
                id: needle.id,
                id_links: needle.id_links,
                link_url: needle.link_url,
                contents: needle.contents,
                original_contents: needle.original_contents,
                date_tweeted: needle.date_tweeted,
                original_date: needle.original_date,
                photo_url: needle.photo_url,
                screen_name: needle.screen_name,
                source: needle.source,
                tid_status: needle.tid_status,
                tid_userid: needle.tid_userid,
                title: needle.title,
                needle: needle
              });
              
              var el = that.tweet.element;
              that._appendTweet(el);
              
              //트윗에 이벤트 붙이기
            events.add(getByClass('tmx_btn_reply', 'a', el)[0], 'click', function(){
                widget_reply(needle.screen_name,needle.tid_status);
            });
                
            events.add(getByClass('tmx_btn_retweet', 'a', el)[0], 'click', function(){
                widget_retweet(needle.screen_name, needle.original_contents);
            });
              
                  
            });
            that._setTotalandMoreCount();
            that._checkAppearance();

            if (this._behavior != 'preloaded') {
              return this;
            }

          }

          return this;
        },
        
        _setTotalandMoreCount: function() {
          
            var a = getByTag(this.tmxHdEl,'a');
            getByTag(a,'span').innerHTML = ' ('+this.total_count+')';
            
            var more = getByTag(this.tmxFtEl,'div');
            getByTag(getByTag(more,'a'),'span').innerHTML = this.more_count+' ';
            return this;
        },
        
        _checkAppearance: function() {
          
            var bd = this.tmxBdEl.offsetHeight;
            var list = this.tmxListEl.offsetHeight;
            
            if(list < bd ){
                this.tmxBdEl.style.height = list+'px';
                this.tmxListEl.style.height = list+'px';
            }
            return this;
        },
        
        _error: function(error_msg) {
            
          this.tweet = new error_tweet(error_msg);
          if (this._isLive && this.runOnce) {
            this.tweet.element.style.opacity = 0;
            this.tweet.element.style.filter = 'alpha(opacity:0)';
            this.tweet.element.style.height = '0';
          }
          
          var el = this.tweet.element;
          this._appendTweet(el);
          this._checkAppearance();
          
          return this;
        },

        // FIXME: This seems like a bug in Occasionally.
        /**
          * @private
          * @return bool
          * tells the job whether to decay
          */
        _decayDecider: function() {
          var r = false;

          if (!this.runOnce) {
            this.runOnce = true;
            r = true;
          }

          else if (this.newResults) {
            r = true;
          }

          return r;
        },

        /**
          * @public
          * @return self
          * starts the cycle
          */
        start: function() {
          var that = this;
          
          if (!this._rendered) {
            setTimeout(function() {
              that.start.call(that);
            }, 50);
            return this;
          }
          if (!this._isLive) {
            this._getResults();
          }
          else {
            this.occasionalJob.start();
          }
          this._isRunning = true;
          this._hasOfficiallyStarted = true;
          return this;
        },
        /**
          * @public
          * @return self
          * stops the cycle
          */
        stop: function() {
          this.occasionalJob.stop();

          if (this.intervalJob) {
            this.intervalJob.stop();
          }

          this._isRunning = false;
          return this;
        },

        /**
          * @public
          * @return self
          * will pause the scrolling, but not stop polling for new results
          * useful for 'hover' interactions
          */
        pause: function() {
          if (this.isRunning() && this.intervalJob) {
            this.intervalJob.stop();
            classes.add(this.widgetEl, 'twtr-paused');
            this._isRunning = false;
          }

          if (this._resumeTimer) {
            clearTimeout(this._resumeTimer);
            this._resumeTimer = null;
          }

          return this;
        },

        /**
          * @public
          * @return self
          * it's like unpausing
          */
        resume: function() {
          var that = this;

          if (!this.isRunning() && this._hasOfficiallyStarted && this.intervalJob) {
            this._resumeTimer = window.setTimeout(function() {
              that.intervalJob.start();
              that._isRunning = true;
              classes.remove(that.widgetEl, 'twtr-paused');
            }, 2000);
          }

          return this;
        },

        /**
          * @public
          * @return bool
          * whether the widget is running
          */
        isRunning: function() {
          return this._isRunning;
        },

        /**
          * @public facade
          * @return self
          * convenience method to stop the cycle, then clear it out
          * widget can be reused if destroyed
          */
        destroy: function() {
          this.stop();
          this.clear();
          this.runOnce = false;
          this._hasOfficiallyStarted = false;
          this._profileImage = false;
          this._isLive = true;
          this._tweetFilter = false;
          this._isScroll = false;
          this.newResults = false;
          this._isRunning = false;
          this.sinceId = 1;
          this.results = [];
          this.showedResults = [];
          this.occasionalJob.destroy();

          if (this.jsonRequestRunning) {
            clearTimeout(this.jsonRequestTimer);
          }

          //classes.remove(this.widgetEl, 'twtr-scroll');
          this.removeEvents();
          return this;
        }
      };
    }();
  })();
})(); // #end application closure
