﻿// ===================================================================
// TEST JAVASCRIPT OBJECT TYPES
// ===================================================================
// LIMITATION: If you try to test for undefined (or other type) on a
// never mentioned object, you will be unable to call ths functions.
//
//  example 1:
//    var objTest;
//    alert(ObjectDetection.IsUndefined(objTest));
//  is acceptable as objTest has been reference even though it hasn't
//  been defined
//
//  example 2:
//    var objTest = new Object();
//    alert(ObjectDetection.IsUndefined(objTest.PropertyTest));
//  is acceptable as objTest is defined and its properties can be
//  tested for definition even if they are not reference.
//
//  example 3:
//    alert(ObjectDetection.IsUndefined(objNeverReferenced));
//  will NOT work as you can't pass an object to a function if that
//  object has never been reference.
//
//  example 4.1: Test for a function in javascript
//    alert(ObjectDetection.IsFunction(fncNeverReferenced));
//  will not work if fncNeverReference has indeed never been
//  referenced.
//  
//  example 4.2: Test for a function in javascript
//    alert(ObjectDetection.IsFunction(window.fncNeverReferenced));
//  WILL work even if fncNeverReference has never been reference as
//  testing properties of an existing object is permissible
// ===================================================================

var ObjectDetection = new CObjectDetection();
function CObjectDetection()
{
    // ==============================================
    // Test whether object is initialised
    // ==============================================
    this.IsUndefined = IsUndefined;
    function IsUndefined(objIn)
    {
        return (typeof(objIn) == "undefined");
    }

    // ==============================================
    // Test whether object is Null
    // ==============================================
    this.IsNull = IsNull;
    function IsNull(objIn)
    {
        return (IsObject(objIn, true) && (objIn == null));
    }

    // ==============================================
    // Test whether object is an object (not inc.
    // number, string or function)
    // ==============================================
    this.IsObject = IsObject;
    function IsObject(objIn, bAllowNull)
    {
        // Optional parameter, default false
        if ((typeof(bAllowNull) == "undefined") || (bAllowNull != true))
            bAllowNull = false;

        // If not object (eg. undefined, or string), return false
        if (typeof(objIn) != "object")
            return;

        // If null not allowed, ensure value isn't null
        return ((bAllowNull) || (objIn != null));
    }

    // ==============================================
    // Test whether object is an array
    // ==============================================
    this.IsArray = IsArray;
    function IsArray(objIn)
    {
        // Now check for Number objects
        return (IsObject(objIn) && (objIn.constructor == Array));
    }

    // ==============================================
    // Test whether object is boolean
    // ==============================================
    this.IsBoolean = IsBoolean;
    function IsBoolean(objIn)
    {
        return (!IsUndefined(objIn) && ((objIn == false) || (objIn == true)));
    }

    // ==============================================
    // Test whether object is a string
    // ==============================================
    this.IsString = IsString;
    function IsString(objIn)
    {
        // First test detects strings initialised as literal
        // - eg. objIn = "string"
        // Seconds tes detects string initialised as object
        // - eg. objIn = new String("string")
        return ((typeof(objIn) == "string")
             || (IsObject(objIn) && (objIn.constructor == String)));
    }

    // ==============================================
    // Test whether object is numeric (not inc. NaN)
    // ==============================================
    this.IsNumber = IsNumber;
    function IsNumber(objIn)
    {
        // If defined as a number literal and not NaN, return true
        if ((typeof(objIn) == "number") && isFinite(objIn))
            return true;

        // Now check for Number objects
        return (IsObject(objIn) && (objIn.constructor == Number) && isFinite(objIn));
    }
    
    // ==============================================
    // Test whether object is an integer
    // ==============================================
    this.IsInteger = IsInteger;
    function IsInteger(objIn)
    {
        // If value isn't a number, it can't be an integer
        // NB: We're testing for an integer object, not an integer
        // representation held in a string, for example
        if (!IsNumber(objIn))
            return false;
            
        // Ensure number is in fact an integer
        return (objIn == parseInt(objIn))
    }
    

    // ==============================================
    // Test whether object is a date
    // ==============================================
    this.IsDate = IsDate;
    function IsDate(objIn)
    {
        return (IsObject(objIn) && (objIn.constructor == Date));
    }

    // ==============================================
    // Test whether object is a function
    // ==============================================
    this.IsFunction = IsFunction;
    function IsFunction(objIn)
    {
        // Not sure why we don't need to do the multiple checks like for string and
        // number (eg. objIn = new Function("")), but it seems to work without)
        return (typeof(objIn) == "function");
    }

    // ==============================================
    // Generic test function (note: this won't work
    // with objects that can be created as objects
    // or literals - eg. IsString)
    // ==============================================
    this.IsType = IsType;
    function IsType(objIn, objType)
    {
        return (IsObject(objIn)
             && !IsUndefined(objType)
             && (objIn.constructor == objType));
    }
}
