/**
 * Collections of functions for daapi
 *
 * @see daapi_header.xt
 */

// Global variables
var userInfo = new Array();
/**
 * @const CONTENT_TYPES
 * Hash with every content type
 */
var CONTENT_TYPES = {
    'Article': new ContentType('Article'),
    'UserPhoto': new ContentType('UserPhoto'),
    'PublicPhoto': new ContentType('PublicPhoto'),
    'PublicVideo': new ContentType('PublicVideo'),
    'UserPhotoGallery': new ContentType('UserPhotoGallery'),
    'PublicPhotoGallery': new ContentType('PublicPhotoGallery'),
    'PublicVideoGallery': new ContentType('PublicVideoGallery'),
    //'PublicBlog': new ContentType('PublicBlog'),
    //'GroupBlog': new ContentType('GroupBlog'),
    'UserBlog': new ContentType('UserBlog'),
    'BlogPost': new ContentType('BlogPost'),
    'Discussion': new ContentType('Discussion'),
    'Persona': new ContentType('Persona')
};

/**
 * @const PERSONA_LINK
 * link to persona
 */
var PERSONA_LINK = 'index.php/base/persona?userId=';

// Functions

/**
 * Procedure sendRequest
 * Send a request to the pluck server
 *
 * @param Array requests
 * @param Function callback
 */
function sendRequest(requests, callback){
    var listOfRequests = null;
    var requestBatch = new RequestBatch();

    if(requests instanceof Array) 
        listOfRequests = requests;
    else
        listOfRequests = new Array(requests);
    
    for(var i = 0; i < listOfRequests.length; i++)
        requestBatch.AddToRequest(listOfRequests[i]);

    requestBatch.BeginRequest(gDaapiUrl, callback);
}

/**
 * Procedure getNumberOfComments
 * Print the article's number of comment in a tag
 *
 * @param Tag tag
 * @param Integer aid
 */
function getNumberOfComments(tag, aid){
    var articleKey = new ArticleKey(aid);

    if(tag = getTag(tag)){
        sendRequest(articleKey, function(responseBatch){
            if(responseBatch.Responses.length == 0)
                tag.innerHTML = 0;
            else{
                var article = responseBatch.Responses[0].Article;
                tag.innerHTML = article.Comments.NumberOfComments;
            }
        });
    }
}

/**
 * Procedure getNumberOfMessages
 * Print the user's number os messages in a tag
 *
 * @param Tag tag
 * @param Integer uid
 */
function getNumberOfMessages(tag, uid){
    var userKey = new UserKey(uid);
    var msgPage = new PersonaMessagePage(userKey, 10, 1, 'TimeStampDescending');
    
    if(tag = getTag(tag)){
        sendRequest(msgPage, function(responseBatch){
            if(responseBatch.Responses.length == 0)
                tag.innerHTML = 0;
            else{
                var page = responseBatch.Responses[0].PersonaMessagePage;
                tag.innerHTML = page.NumberOfMessages;
            }
        });
    }
}

/**
 * Function getTag
 * Get the tag object from its id
 *
 * @param String/Object tag
 *
 * @return Object
 */
function getTag(tag){
    if(typeof(tag) == 'string'){
        try{
            tag = document.getElementById(tag);
        }
        catch(e){
            tag = null;
        }
    }

    return tag;
}

/**
 * Procedure getContent
 * Get content per each contentype and trigger the callback function passing that result
 *
 * @param Array/String sections
 * @param Array/String categories
 * @param Array/String contributors
 * @param String activity
 * @param Array/String contentypes
 * @param Integer age
 * @param Array/Integer numitems
 * @param Function callback
 *
 * @return Hash
 */
function getContent(sections, categories, contributors, contentypes, activity, age, numitems, callback){
    var searchSections = [];
    var searchCategories = [];
    var limitToContributors = [];
    var activityContent = new Activity(activity);
    
    sections = string2Array(sections, ',');
    for (var i = 0; i < sections.length; i++)
        searchSections.push(new Section(sections[i]));

    categories = string2Array(categories, ',')
    for (var i = 0; i < categories.length; i++)
        searchCategories.push(new Category(categories[i]));

    contributors = string2Array(contributors, ',');
    for (var i = 0; i < contributors.length; i++)
        limitToContributors.push(new UserTier(contributors[i]));

    contentypes = string2Array(contentypes, ',');
    numitems = string2Array(numitems, ',');

    var requests = [];
    var contentype = '';
    var nitems = '';

    for(var i = 0; i < contentypes.length; i++){
        nitems = parseInt((i < numitems.length) ? numitems[i] : numitems[numitems.length-1]);

        var discoveryAction = new DiscoverContentAction(
            searchSections,
            searchCategories,
            limitToContributors,
            activityContent,
            CONTENT_TYPES[contentypes[i]],
            age,
            nitems
        );

        requests.push(discoveryAction);
    }

    sendRequest(requests, function(responseBatch){
        if(responseBatch.Responses.length > 0){
            var content = {};
            var discoveredContent = null;
            
            for(var i = 0; i < responseBatch.Responses.length; i++){
                discoveredContent = responseBatch.Responses[i].DiscoverContentAction.DiscoveredContent;
                
                // add userkey to special cases
                var userId = '';

                for(var j = 0; j < discoveredContent.length; j++){
                    // special cases where user information is missing
                    switch(contentypes[i]){
                        case 'UserPhotoGallery':
                        case 'PublicPhotoGallery':
                        case 'PublicVideoGallery':
                            userId = getParamFromURL(discoveredContent[j].Permalink, 'userId');
                            break;
                        case 'UserBlog':
                        case 'GroupBlog':
                        case 'PublicBlog':
                            userId = getParamFromURL(discoveredContent[j].BlogUrl, 'userId');
                            break;
                    }
                    if(userId != '')
                        discoveredContent[j]['UserKey'] = {'Key': userId};
                }
                content[contentypes[i]] = discoveredContent;
            }
            callback(content);
        }
    });

}

/**
 * Function string2Array
 * Turn a string into an array depending on a separator
 *
 * @param String/Array data
 * @param String sep
 *
 * @return Array
 */
function string2Array(data, sep){
    if(typeof(data) == 'string')
        return data.split(sep);
    if(typeof(data) == 'number')
        return [data];
    else if(data instanceof Array)
        return data;
    else
        return [];
}

/**
 * Procedure preLoadGetEvents
 * Check whether or not to call getEvent procedure in onload event, because of a problem in IE.
 *
 * @see getEvents
 *
 * @param Boolean onload
 */
function preLoadGetEvents(onload, sections, categories, contributors, contentypes, activity, age, numitems, options){
    if(onload){
        // this procedure is always called in onload event
        jQuery(document).ready(function(){
            getEvents(sections, categories, contributors, contentypes, activity, age, numitems, options);
        });
    }
    else{
        // in IE we cannot call the function in onload event otherwise it'll throw an error (security issue)
        if(jQuery.browser.msie){
            jQuery(document).ready(function(){
                getEvents(sections, categories, contributors, contentypes, activity, age, numitems, options);
            });
        }
        else
            getEvents(sections, categories, contributors, contentypes, activity, age, numitems, options);
    }
}

/**
 * Procedure getEvents
 * Get events in every contentype and depending on the activity
 *
 * @see __endGetEvents procedure
 *
 * @param Array/String sections
 * @param Array/String categories
 * @param Array/String contributors
 * @param Array/String contentypes
 * @param Integer age
 * @param Array/Integer numitems
 * @param Object options
 */
function getEvents(sections, categories, contributors, contentypes, activity, age, numitems, options){
    var options = options || {};
    var missingAuthors = options.missingAuthors || false;

    // we have to preserve this parameter in case of we want an ordered list with x number of items
    options['numitems'] = numitems;

    if(typeof(contentypes) == 'string'){
        if(contentypes.toLowerCase() == 'all'){
            contentypes = [];
            for(var p in CONTENT_TYPES){
                if(p == 'Article') // Article is excluded, it's not interesting
                    continue;
                else
                    contentypes.push(p);
            }
        }
        else
            contentypes = string2Array(contentypes, ',');
    }

    // get the last content in every contentype. One per each contentype
    getContent(sections, categories, contributors, contentypes, activity, age, numitems, function(content){
        var datas = {};
        var avaliables = [];
       
        for(var p in content){
            if(content[p].length == 0)
                continue;

            datas[p] = [];
            avaliables.push(p);
            
            for(var i = 0; i < content[p].length; i++){
                //if(content[p][i].length == 0)
                //    continue;

                // make generalizations about the most commun properties
                switch(p){
                    case 'UserPhoto':
                    case 'PublicPhoto':
                        content[p][i].Author['Link'] = PERSONA_LINK + content[p][i].Author.UserKey.Key;
                        datas[p][i] = {
                            'author': content[p][i].Author,
                            'avatar': content[p][i].Image.Small ? content[p][i].Image.Small : content[p][i].Author.AvatarPhotoUrl,
                            'event': content[p][i].Title,
                            'url': content[p][i].PhotoUrl,
                            'date': string2Date(content[p][i].CreatedOn)
                        };
                        break;
                    case 'PublicVideo':
                        content[p][i].Author['Link'] = PERSONA_LINK + content[p][i].Author.UserKey.Key;
                        datas[p][i] = {
                            'author': content[p][i].Author,
                            'avatar': content[p][i].VideoThumbnail ? content[p][i].VideoThumbnail : content[p][i].Author.AvatarPhotoUrl,
                            'event': content[p][i].Title,
                            'url': content[p][i].VideoUrl,
                            'date': string2Date(content[p][i].CreatedOn)
                        };
                        break;
                    case 'UserPhotoGallery':
                    case 'PublicPhotoGallery':
                    case 'PublicVideoGallery':
                        datas[p][i] = {
                            'author': content[p][i].UserKey.Key,
                            'avatar': '',
                            'event': content[p][i].Title,
                            'url': content[p][i].Permalink,
                            'date': string2Date(content[p][i].CreatedOn)
                        };
                        break;
                    case 'PublicBlog':
                    case 'GroupBlog':
                    case 'UserBlog':
                        datas[p][i] = {
                            'author': content[p][i].UserKey.Key,
                            'avatar': content[p][i].AvatarUrl,
                            'event': content[p][i].Title,
                            'url': content[p][i].BlogUrl,
                            'date': ''
                        };
                        break;
                    case 'BlogPost':
                        content[p][i].PostAuthor['Link'] = PERSONA_LINK + content[p][i].PostAuthor.UserKey.Key;
                        datas[p][i] = {
                            'author': content[p][i].PostAuthor,
                            'avatar': content[p][i].PostAuthor.AvatarPhotoUrl,
                            'event': content[p][i].PostTitle,
                            'url': content[p][i].Url,
                            'date': string2Date(content[p][i].PostDate)
                        };
                        break;
                    case 'Discussion':
                        datas[p][i] = {
                            'author': content[p][i].UserKey.Key,
                            'avatar': '',
                            'event': content[p][i].DiscussionTitle,
                            'url': content[p][i].DiscussionUrl,
                            'date': string2Date(content[p][i].LastUpdated)
                        };
                        break;
                    case 'Persona':
                        content[p][i]['Link'] = PERSONA_LINK + content[p][i].UserKey.Key,
                        datas[p][i] = {
                            'author': content[p][i],
                            'avatar': content[p][i].AvatarPhotoUrl,
                            'event': content[p][i].DisplayName,
                            'url': content[p][i].Link,
                            'date': string2Date(content[p][i].LastUpdated)
                        }
                        break;
                }

                // we need to format the date
                datas[p][i]['strDate'] = extractDate(datas[p][i]['date'], '/');
                datas[p][i]['strTime'] = extractTime(datas[p][i]['date'], 12);

                // keep the contentype in each record
                datas[p][i]['contentype'] = p;

                // store the content just in case we need it
                datas[p][i]['content'] = content[p][i];
                
                /* 
                // get the author if we don't have information about it, just the author key
                if(typeof(datas[p][i]['author']) == 'string')
                    getAuthor(datas, p, i);
                */
            }
        }

        // preserve this array for later
        options['avaliables'] = avaliables;
       
        if(missingAuthors)
            getMissingAuthors(datas, options);
        else
            __endGetEvents(datas, options);
    });
}

/**
 * Function extractDate
 *
 * @param Date objDate
 * @Param String sep
 *
 * @return String
 */
function extractDate(objDate, sep){
    var dd, mm, yyyy;

    if(objDate instanceof Date){
        dd = objDate.getDate() < 10 ? '0' + objDate.getDate() : objDate.getDate();
        mm = objDate.getMonth() < 9 ? '0' + (objDate.getMonth()+1) : (objDate.getMonth()+1);
        yyyy = objDate.getFullYear();
        return dd + sep + mm + sep + yyyy;
    }
    else
        return '';

}

/**
 * Function extractTime
 *
 * @param Date objDate
 * @param Integer h (only value 12)
 *
 * @return String
 */
function extractTime(objDate, h){
    var hh, mm, ss;
    
    if(objDate instanceof Date){ 
        hh = (h == 12 ? (objDate.getHours() > h ? objDate.getHours() - h : (objDate.getHours() == 0 ? h : objDate.getHours())) : objDate.getHours());
        mm = objDate.getMinutes() < 10 ? '0' + objDate.getMinutes() : objDate.getMinutes();
        ss = objDate.getSeconds() < 10 ? '0' + objDate.getSeconds() : objDate.getSeconds();
        return hh + ':' +  mm + ':' + ss + (h == 12 ? (objDate.getHours() > h ? ' pm' : ' am') : '');
    }
    else
        return '';
}

/**
 * Procedure getMissingAuthors
 * Retrieve every missing author from datas
 *
 * @param Object datas
 * @param Object options
 */
function getMissingAuthors(datas, options){
    var data = {};
    var pos = [];
    var userkeys = [];
    
    // check missing authors and store them
    for(var p in datas){
        for(var i = 0; i < datas[p].length; i++){
            data = datas[p][i];
            if(typeof(data.author) == 'string' && data.author != ''){
                userkeys.push(new UserKey(data.author));
                pos.push({'p': p, 'i': i}); // save the position within datas
            }
        }
    }
    
    // get missing authors
    if(userkeys.length > 0){
        sendRequest(userkeys, function(responseBatch){
            if(responseBatch.Responses.length > 0){
                var content = {};
                var p, i;
                for(var j = 0; j < responseBatch.Responses.length; j++){
                    p = pos[j]['p'];
                    i = pos[j]['i'];

                    responseBatch.Responses[j].User['Link'] = PERSONA_LINK + responseBatch.Responses[j].User.UserKey.Key;
                    datas[p][i]['author'] = responseBatch.Responses[j].User;

                    if(datas[p][i]['avatar'] == '')
                        datas[p][i]['avatar'] = responseBatch.Responses[j].User.AvatarPhotoUrl;

                    datas[p][i]['content']['User'] = responseBatch.Responses[j].User;
                }
                __endGetEvents(datas, options);
            }           
        });
    }
    else
        __endGetEvents(datas, options);
}

/**
 * Private Procedure __endGetEvents
 * Final process in getEvent procedure
 *
 * @see getEvents procedure
 *
 * @param Object datas
 * @param Object options
 */
function __endGetEvents(datas, options){
    var options = options || {};
    var element = options.element || '';
    var template = options.template || '';
    var callback = options.callback || (template ? null : function(datas){
        // By default;
    });
    var rndct = options.rndct || 0;
    var sort = options.sort || '';
    var avaliables = options.avaliables || [];
    var numitems = options.numitems || 20;

    var result = null; // Object or Array

    if(rndct && avaliables.length > rndct){
        // choose "rndct" random contentypes
        var randomNums = getRandomNumbers(rndct, avaliables.length - 1);

        if(randomNums instanceof Array){
            for(var i = 0; i < randomNums.length; i++)
                result[avaliables[randomNums[i]]] = datas[avaliables[randomNums[i]]];
        }
    }
    else
        result = datas;
  
    // if there is only one contentype or we want to order, then
    // we change the structure of data object into a list
    if(avaliables.length == 1 || sort){
        var list = [];
       
        for(var p in result){
            for(var i = 0; i < result[p].length; i++){
                list.push(result[p][i]); 
            }
        }

        if(sort) list = orderByDate(list, sort);
        
        // truncate the list
        if(list.length > numitems)
            result = list.slice(0, numitems);
        else
            result = list;
    }
   
    if(element){
        var events = [];

        if(result instanceof Array)
            events = result;
        else{
            // change the structure of data object to be able to pass it properly to the template
            for(var p in result)
                events.push(result[p]); // Array of Arrays
        }
        
        jQuery(element).setTemplateURL(template);
        jQuery(element).processTemplate({'events': events});
    }
    else
        callback(result);
}

/**
 * Procedure getAuthor
 * Get the author object from a userkey in datas structure (from getEvents)
 *
 * @param Object datas (by reference)
 * @param String ctype
 * @param Integer index
 */
function getAuthor(datas, p, i){
    var key;
    
    if(typeof(datas[p][i]['author']) == 'string'){
        key = datas[p][i]['author'];
        getUser(key, function(user){
            datas[p][i]['author'] = user[key];
            if(datas[p][i]['avatar'] == '')
                datas[p][i]['avatar'] = user[key].AvatarPhotoUrl;
        });
    }
}

/**
 * Function getParamFromURL
 * Return the param from a url
 *
 * @param String url
 * @param String key
 *
 * @return String
 */
function getParamFromURL(url, key){
    var aux1;
    var aux2;
    
    if(url && key){
        aux1 = url.split('?');
        aux1 = aux1[1].split('&');
        for(var i = 0; i < aux1.length; i++){
            aux2 = aux1[i].split('=');
            if(aux2[0] == key)
                return aux2[1];
        }
        return ''
    }
    else
        return '';
}

/**
 * Function getRandomNumbers
 * Return "num" random numbers
 *
 * @param Integer num
 * @param Integer limit
 *
 * @return Integer/Array
 */
function getRandomNumbers(num, limit){
    var randomNums = []
    var ranNum = null;
    var inArray = false;
    
    do{
        ranNum = Math.floor(Math.random() * (limit + 1));
        if(randomNums.length == 0)
            randomNums.push(ranNum);
        else{
            inArray = false;
            for(var i = 0; i < randomNums.length && !inArray; i++){
                if(randomNums[i] == ranNum)
                    inArray = true;
            }

            if(!inArray) randomNums.push(ranNum);
        }
    }while(randomNums.length < num);
    
    if(randomNums.length == 1) return randomNums[0];
    else return randomNums;
}

/**
 * Procedure getUser
 * Get the user
 *
 * @param String/Array userkeys
 * @param Function callback
 */
function getUser(userkeys, callback){
    var searchUserkeys = [];

    userkeys = string2Array(userkeys, ',');
    for(var i = 0; i < userkeys.length; i++)
        searchUserkeys.push(new UserKey(userkeys[i].toString()));

    sendRequest(searchUserkeys, function(responseBatch){
        if(responseBatch.Responses.length > 0){
            var content = {};
            for(var i = 0; i < responseBatch.Responses.length; i++)
                content[responseBatch.Responses[i].User.UserKey.Key] = responseBatch.Responses[i].User;
            
            callback(content);
        }
    });
}

/**
 * Function string2Date
 * Turn a date ("mm/dd/yyyy hh:mm:ss AM/PM" format) into a date object
 *
 * @param String sdate
 *
 * @return Date
 */
function string2Date(sdate){
    var yy, mm, dd, h, m, s;
    var aux = [];
    var parts = sdate.split(' ');

    if(parts.length == 3){
        aux = parts[0].split('/'); // date
        dd = parseInt(aux[1]); // day
        mm = parseInt(aux[0]) - 1; // month
        yy = parseInt(aux[2]); // year

        aux = parts[1].split(':'); // hour
        if(aux[0] == '12'){
            if(parts[2].toLowerCase() == 'pm')
                h = 12;
            else
                h = 0;
        }
        else{
            if(parts[2].toLowerCase() == 'pm')
                h = 12 + parseInt(aux[0]);
            else
                h = parseInt(aux[0]);
        }

        m = aux[1];
        s = aux[2];
    }

    return new Date(yy, mm, dd, h, m, s);
}

/**
 * Function orderByDate
 * Order and array by date depending on the type of order (bubblesort)
 * NOTE: the objects got to have a Date object field called "date"
 *
 * @param Array datas
 * @param String name
 * @param String type
 *
 * @return Array
 */
function orderByDate(datas, type){
    var aux, start, rest;

    if(datas instanceof Array){
        
        start = 0;
        rest = datas.length;

        for(var i = rest - 1; i > start;  i--){
            for(var j = start; j < i; j++) {
                if(datas[j]['date'] > datas[j+1]['date']){
                    if(type.toLowerCase() == 'asc'){
                        aux = datas[j];
                        datas[j] = datas[j+1];
                        datas[j+1] = aux;
                    }
                }
                else{
                    if(type.toLowerCase() == 'desc'){
                        aux = datas[j+1];
                        datas[j+1] = datas[j];
                        datas[j] = aux;
                    }
                }
            }
        }
    }

    return datas;
}

/**
 * Procedure printAvatar
 * Set the src property in a img element
 *
 * @param String/Object tag
 * @param Integer/String uid
 */
function printAvatar(tag, uid){
    if(tag = getTag(tag)){
        if(tag.tagName.toLowerCase() == 'img'){ // just in img elements
            getUser(uid, function(user){
                tag.src = user[uid].AvatarPhotoUrl;
            });
        }
    }
}

/**
 * Procedure getInfoUserDropdown
 * get info for user dropdown (avatar, number of messages)
 *
 * @see getNumberOfMessages
 * @see printAvatar
 *
 * @param Tag imgTag
 * @param Tag numTag
 * @param Integer/String uid
 */
function getInfoUserDropdown(imgTag, numTag, friendTag, uid){
    var userKey = new UserKey(uid.toString());
    var msgPage = new PersonaMessagePage(userKey, 10, 1, 'TimeStampDescending');

    imgTag = getTag(imgTag);
    numTag = getTag(numTag);
    friendTag = getTag(friendTag);

    var requests = [userKey, msgPage];

    sendRequest(requests, function(responseBatch){
        if(responseBatch.Responses.length == 0){
            tag.innerHTML = 0;
        }
        else if(responseBatch.Responses.length == 2){
            var user = responseBatch.Responses[0].User;
            var page = responseBatch.Responses[1].PersonaMessagePage;

            imgTag.src = user.AvatarPhotoUrl;
            numTag.innerHTML = page.NumberOfMessages;
            friendTag.innerHTML = user.NumberOfPendingFriends;
            $('user_location').innerHTML = user.Location;

            // Issue 5759
            try{
                if(user.NumberOfPendingFriends > 0)
                    $('navigationsec').className = 'user friends';
                else
                    $('navigationsec').className = 'user';
            }
            catch(e){;}
        }
    });
}

