/**
 * @author Jae Cho
 * set of utility functions
 */



/**
 * context bind method
 * in JS, the keyword 'this' means the current closure instead of the
 * object in which the method is defined. This causes problems in callback
 * methods. Use this bind method to bind object to the method
 * got it from http://fn-js.info/snippets/bind
 * @param obj
 * @param fun
 * @param args
 */
function bindContext(obj, fun, args) {
  return function() {
    if (obj === true)
      obj = this;
    var f = typeof fun === "string" ? obj[fun] : fun;

    return f.apply(obj, Array.prototype.slice.call(args || [])
        .concat(Array.prototype.slice.call(arguments)));
  };
}




/**
* CookieUtil
* utility class for handling cookies
* copied from http://www.quirksmode.org/js/cookies.html
*/
function CookieUtil() {

    /** create cookie
     *
     * @param name
     * @param value
     * @param days
     */
    this.createCookie = function(name,value,days) {
        if (days) {
            var date = new Date();
            date.setTime(date.getTime()+(days*24*60*60*1000));
            var expires = "; expires="+date.toGMTString();
        }
        else var expires = "";
        document.cookie = name+"="+value+expires+"; path=/";
    };

    /**
     * read cookie
     * @param name
     */
    this.readCookie = function(name) {
        var nameEQ = name + "=";
        var ca = document.cookie.split(';');
        for(var i=0;i < ca.length;i++) {
            var c = ca[i];
            while (c.charAt(0)==' ') c = c.substring(1,c.length);
            if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
        }
        return null;
    };

    /**
     * erase cookie
     * @param name
     */
    this.eraseCookie = function(name) {
        createCookie(name,"",-1);
    };
}

/**
 * StringUtil
 */
function StringUtil() { }

/** delimiters used to input multiple email addess */
StringUtil.EMAIL_DELIMITER_PATTERN = /[\,\r\n\f\v:]+/;

/** pattern for email */
StringUtil.EMAIL_PATTERN = /^(?:[\w\.])+@(?:[\w]+)(?:\.(?:[\w])+)+/;

/** pattern for name jae <jaecho@yo.com> */
StringUtil.NAME_PATTERN1 = /<([\S+]+)>\s*([\w ]+)/;
StringUtil.NAME_PATTERN2 = /([\w ]+)\s*<([\S+]+)>/;


/** returns true if str is a valid email */
StringUtil.isValidEmail = function(str) {
    return str.match(this.EMAIL_PATTERN);
};

StringUtil.trim = function (stringToTrim) {
    return stringToTrim.replace(/^\s+|\s+$/g,"");
};


/** @return array of email objects for each entry
* status - valid, invalid
* email - parsed email address
* name - name if < > is provided
*/
StringUtil.parseEmails = function(emails) {
    var entries = emails.split(this.EMAIL_DELIMITER_PATTERN);
    var parsedEntries = new Array();

    for (var i = 0; i < entries.length; i++) {

        var string = entries[i];
        if (!string) continue;

        string = this.trim(string);

        var parsedEntry  = this.parseEntry(string);
        parsedEntries.push(parsedEntry);

        if (this.EMAIL_PATTERN.test(parsedEntry.email)) {
            parsedEntry.status = "valid";
        } else {
            parsedEntry.status = "invalid";
        }
    }
    return parsedEntries;
};

/**
 * parse an entry in email list string into name and email address.
 * @param string
 */
StringUtil.parseEntry = function(string) {
    var res;
    var parsedEntry = new Object();
    parsedEntry.string = string;

    res = string.match(this.NAME_PATTERN1);
    if (res) {
        parsedEntry.name = res[2];
        parsedEntry.email = res[1];
        return parsedEntry;
    }

    res = string.match(this.NAME_PATTERN2);
    if (res) {
        parsedEntry.email = res[2];
        parsedEntry.name = res[1];
        return parsedEntry;
    }

    parsedEntry.email = string;
    return parsedEntry;
};



/** return a map containing request query parameters and values in string
 * for example, request with http://yo.com?v0=1&v1=2 will return
 * { "v0" : "1", "v1" : "2" }
 * @param queryStr value of window.location.search variable
 */
StringUtil.getQueryParams = function(queryStr) {

    var query = queryStr.substring(1);
    var vars = query.split("&");
    for (var i=0;i<vars.length;i++) {
        var pair = vars[i].split("=");
        vars[pair[0]] = pair[1];
    }
    return vars;
};

/** return a string chopped up into n characters, separated by spaces.
 * This is used to force a wrap on extra long words, to prevent display issues
 *
 * @param str = string to be chopped
 * @param charMax = number of characters per segment
 */
StringUtil.wordChopper = function(str, charMax){
    if (!str) return str;

    var strArr = str.split(" ");
    for (i=0;i<strArr.length;i++){
       var charCount = strArr[i].length;
       if (charCount < charMax){
           //don't modify the string
           continue;
       }
      var segCount = charCount / charMax;
      var newStr = "";
      for (j=0; j<=segCount;j++){
          newStr += strArr[i].substr(j*charMax,charMax) + " ";
      }
      strArr[i] = newStr;
    }
  return strArr.join(" ");
}
/**
 * DateUtil
 */
function DateUtil() { }

DateUtil.SECOND_MS = 1000;
DateUtil.MIN_MS = DateUtil.SECOND_MS * 60;
DateUtil.HOUR_MS = DateUtil.MIN_MS * 60;
DateUtil.DAY_MS = DateUtil.HOUR_MS * 24;


DateUtil.calculateAge = function(time1, time2) {
    var diff = time1 - time2;
    return DateUtil.formatAge(diff);
};

DateUtil.formatAge = function(ageInMs) {

    var diffInUnit;
    var unit;

    if (ageInMs <= DateUtil.MIN_MS) {
        diffInUnit = Math.round(ageInMs / DateUtil.SECOND_MS);
        unit = diffInUnit == 1 ? "second" : "seconds";
    } else if (ageInMs <= DateUtil.HOUR_MS) {
        diffInUnit = Math.round(ageInMs / DateUtil.MIN_MS);
        unit = diffInUnit == 1 ? "minute" : "minutes";
    } else if (ageInMs <= DateUtil.DAY_MS) {
        diffInUnit = Math.round(ageInMs / DateUtil.HOUR_MS);
        unit = diffInUnit == 1 ? "hour" : "hours";
    } else {
        diffInUnit = Math.round(ageInMs / DateUtil.DAY_MS);
        unit = diffInUnit == 1 ? "day" : "days";
    }

    return diffInUnit + " " + unit;
};

DateUtil.dojoDifference = function(date1, date2, period) {
    return dojo.date.difference(date1, date2, period);
};

function ProfileUtil() {};

/**
 * get profile image path
 * @param args - map of various argments
 * - userId or userUuid - one of them is required
 * - size (optional) - "large" or "small (default)"
 * If true, server will show image in moderation queue if present.
 * If true, append date string so that browser does not cache the image
 */
ProfileUtil.getImg = function(args) {
    var path = "/dynamic/photo/userPic?";
    var defaultPath = "/static/images/user_pic_default_";
    var self = false;
    var cutil = new CookieUtil();

    if (!args.userPicSet && typeof args.userPicSet != "undefined"){
        if (args.size)return defaultPath + args.size + ".jpg";
        else return defaultPath + "small.jpg";
    }
    if (args.userId) {
        path += "userId=" + args.userId;
        if (cutil.readCookie("aguseridsc") == args.userId) self = true;

    } else if (args.userUuid) {
        path += "userUuid=" + args.userUuid;
        if (cutil.readCookie("aguseruuidsc") == args.userUuid) self = true;

    } else {
        return null;
    }

    if (args.size == "big") path += "&thumbnail=false";
    else path += "&thumbnail=true";

    if (self) {
        path += "&self=true";
        path += "&date=" + (new Date()).getTime();
    }
    return path;
};