﻿
// Samples:
// From(people).Where("ID", op.Equals, id).Select("*");
// From(people).Where("FirstName", op.Equals, firstName).Select("*");
// From(people).OrderBy("LastName").Select(["LastName"]);
// From(people).Where(function(item){return item.ID > 3;}).OrderBy("ID").Select("*");

var jslinq = window.jslinq = (function(){
    
    var JSLinqObject = function(array)
    {
        this._array = array;
    };

    // Operators
    var op = {
        Equals : "===",
        NotEquals : "!==",
        GreaterThan : ">",
        LessThan : "<",
        GreaterThanOrEquals : ">=",
        LessThanOrEquals : "<=",
        Identical : "==",
        NotIdentical : "!="
    };
    
    JSLinqObject.GetOperators = function()
    {
        return op;
    };

    var From = window.From = function(array)
    {
        /// <summary>From LINQ to JavaScript Operator. This method was included to support it's LINQ counterpart.<</summary>
        /// <param name="array">The Array with the source items.</param>
        /// <returns type="JSLinqObject">JSLinqObject</returns>
        var obj = new JSLinqObject(array);
        return obj;
    };

    JSLinqObject.prototype = 
    {
        __typeName : 'JSLinqObject',
        __class : true,
        GetArray : function()
        {
            return this._array;
        },
        Get : function(index)
        {
            return this._array[index];
        },
        Where : function(propertyName, operator, propertyValue)
        {
            /// <summary>Where LINQ to JavaScript Operator</summary>
            /// <param name="propertyName">The property name on the item.</param>
            /// <param name="operator">The operator to test for a match.</param>
            /// <param name="propertyValue">The value to test against for a match.</param>
            /// <returns type="JSLinqObject">JSLinqObject</returns>

            var sourceItems = this.GetArray();
            var items = new Array();
            
            if(typeof(propertyName) == "string")
            {
                // The propertyName was passed in as a String
                for(var i = 0; i < sourceItems.length; i++)
                {
                    var item = sourceItems[i];
                    var itemValue = item[propertyName];
                    var result = false;
                    if (operator === op.Equals)
                    {
                        result = (itemValue === propertyValue);
                    }
                    else if (operator === op.NotEquals)
                    {
                        result = (itemValue !== propertyValue);
                    }
                    else if (operator === op.GreaterThan)
                    {
                        result = (itemValue > propertyValue);
                    }
                    else if (operator === op.LessThan)
                    {
                        result = (itemValue < propertyValue);
                    }
                    else if (operator === op.GreaterThanOrEquals)
                    {
                        result = (itemValue <= propertyValue);
                    }
                    else if (operator === op.LessThanOrEquals)
                    {
                        result = (itemValue <= propertyValue);
                    }
                    else if (operator === op.Identical)
                    {
                        result = (itemValue === propertyValue);
                    }
                    else if (operator === op.NotIdentical)
                    {
                        result = (itemValue != propertyValue);
                    }
                    
                    if (result)
                    {
                        items[items.length] = item;
                    }
                }
            }
            else
            {
                var fn = propertyName;
                // if the propertyName is not a string it must be a function
                // and the function will return the boolean value to determine
                // if the item is a match
                for (var k = 0; k < sourceItems.length; k++)
                {
                    var item2 = sourceItems[k];
                    if (fn(item2))
                    {
                        items[items.length] = item2;
                    }
                }
            }

            return new JSLinqObject(items);
        },
        OrderBy : function(propertyName){
            /// <summary>OrderBy LINQ to JavaScript Operator</summary>
            /// <param name="propertyName">The property name used to determine how to order the data.</param>
            /// <returns type="JSLinqObject">JSLinqObject</returns>
            var fn;
            if (typeof(propertyName) == "string")
            {
                fn = function(item)
                {
                    return item[propertyName];
                };
            }
            else
            {
                fn = propertyName;
            }
            
            var sortFn = function(a, b)
            {
                var x = fn(a);
                var y = fn(b);
                return ((x < y) ? -1 : ((x > y) ? 1 : 0));
            };
            
            var sourceItems = this.GetArray();
            var items = sourceItems.sort(sortFn);
            return new JSLinqObject(items);
        },
        Select : function(propertyNames)
        {
            /// <summary>Select LINQ to JavaScript Operator</summary>
            /// <param name="propertyNames">The property names to select from result items.</param>
            /// <returns type="JSLinqObject">JSLinqObject</returns>
            
            var sourceItems = this.GetArray();
            
            if (propertyNames == "*")
            {
                return this;
            }
            //else if (typeof(propertyNames) == "object" && propertyNames.length)
            else if (propertyNames instanceof Array)
            {
                var items = new Array();
                for(var i = 0; i < sourceItems.length; i++)
                {
                    var item = sourceItems[i];
                    var selection = {};
                    for(var j = 0; j < propertyNames.length; j++)
                    {
                        var propertyName = propertyNames[j];
                        selection[propertyName] = item[propertyName];
                    }
                    items[items.length] = selection;
                    
                }
                return new JSLinqObject(items);
            }
            else if (typeof(propertyNames) == "string")
            {
                // an individual property is requested
                var items2 = new Array();
                for(var k = 0; k < sourceItems.length; k++)
                {
                    var item2 = sourceItems[k];
                    items2[items2.length] = item2[propertyNames];
                }
                return new JSLinqObject(items2);
            }
        }
    };
    
    return JSLinqObject;
})();
