﻿interface IModelAjaxSuccessCallback
{
    (data: any, status: string, request: JQueryXHR): void;
}

interface IAjaxifiedCallback
{
    OnAjaxSuccess: (modelStatus: BasicModelStatus) => void;
}

abstract class AjaxifiedModel extends Model
{
    // Attributes

    // Constructor
    constructor(dataFields: any, primaryKeyName: string, urls: string[])
    {
        super(dataFields, primaryKeyName, urls);
    }

    // Properties

    // Methods
    Create(): boolean
    {
        if (this.PrimaryKey === undefined)  // Can only create once!!
        {
            // Use HTTP POST Request to send string to server
            // GET can be done the same way.
            // Assumes the result returned contains the new primary key value.
            $.post(this.Url(ModelUrlType.Create), this.ToHTMLPairs([this.PrimaryKeyName]), this.OnSuccessCallback(ModelStatus.Created), "html");   // Specify Html being returned
            return true;
        }
        return false;
    }

    Read(): boolean
    {
        if (this.PrimaryKey !== undefined)      // Can only read if primary key is set
        {
            var url: string = this.Url(ModelUrlType.Read, this.PrimaryKeyNameValue);        // Modify url to include primary key

            // Use Http GET Request and send no data.
            $.get(url, this.OnSuccessCallback(ModelStatus.Read), "html");   // Specify Html being returned
            return true;
        }
        return false;
    }

    Update(): boolean
    {
        if (this.PrimaryKey !== undefined)      // Can only update if primary key is set
        {
            // Use HTTP POST Request to send string to server
            // Assumes primary key in model is correct!!
            $.post(this.Url(ModelUrlType.Update), this.ToHTMLPairs(), this.OnSuccessCallback(ModelStatus.Updated), "html");   // Specify Html being returned
            return true;
        }
        return false;
    }

    Delete(): boolean
    {
        if (this.PrimaryKey !== undefined)      // Can only delete if primary key is set
        {
            // Use HTTP POST Request to send string to server
            // GET can be done the same way.
            $.post(this.Url(ModelUrlType.Delete), this.PrimaryKeyNameValue, this.OnSuccessCallback(ModelStatus.Deleted), "html");   // Specify Html being returned
            return true;
        }
        return false;
    }

    protected ReadData(data: any, status: string, request: JQueryXHR, setPrimaryKey: boolean): void
    {
        // Assume data is returned in name/value pairs
        var pairs: string[] = data.split('&');
        var name: string;
        var value: string;

        for (var p of pairs)
        {
            var pair: string[] = p.split('=');
            name = pair[0];
            value = pair[1];
            if (name != this.PrimaryKeyName || setPrimaryKey)
            {
                if (this.SetData(name, value) == false) throw new Error("Incorrect name [" + name + "] or datatype [" + typeof value + "] returned");
            }
        }
    }

    protected CheckForError(data: string): any
    {
        // Assumes errors are returned as a string as follows
        // "error:message"
        var error: string = data.trim();
        var n: number = error.search("error");
        if (n > -1)
        {
            var msg: string[] = error.split(':');
            return msg[1].trim();       // Return the error message
        }
        return false; // No error
    }

    protected OnSuccessCallback(modelStatus: ModelStatus): IModelAjaxSuccessCallback
    {
        var model: AjaxifiedModel = this;

        // Using closure to wrap AJAX success() callback
        return function (data: any, status: string, request: JQueryXHR): void
        {
            if (modelStatus == ModelStatus.Created
            || modelStatus == ModelStatus.Read)
            {
                var error: any = model.CheckForError(data);
                if (error === false) model.ReadData(data, status, request, true);
            }
            model.OnSuccess(modelStatus);
        }
    }

    protected abstract OnSuccess(modelStatus: ModelStatus): void;
}   