var EXPORTED_SYMBOLS = ['windowHelper'];

const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;

Cu.import("resource://gre/modules/XPCOMUtils.jsm");

var jsm = { };
XPCOMUtils.defineLazyGetter(jsm, "utils", function() {
    let obj = { };
    Cu["import"]("resource://livemargins/utils.jsm", obj);
    return obj.utils;
});

XPCOMUtils.defineLazyGetter(jsm, "Services", function() {
    let obj = { };
    Cu["import"]("resource://gre/modules/Services.jsm", obj);
    return obj.Services;
});

XPCOMUtils.defineLazyGetter(jsm, "ctypes", function() {
    let obj = { };
    Cu["import"]("resource://gre/modules/ctypes.jsm", obj);
    return obj.ctypes;
});

XPCOMUtils.defineLazyGetter(this, "logger", function() {
    return jsm.utils.logger('LM4.windowJSM');
});

const RECT = new jsm.ctypes.StructType('RECT',
    [{left:   jsm.ctypes.int32_t},
     {top:    jsm.ctypes.int32_t},
     {right:  jsm.ctypes.int32_t},
     {bottom: jsm.ctypes.int32_t}
    ]);

var ctypesWindowHelper = {
    _user32:        null,
    _findWindow:    null,
    _setWindowPos:  null,
    _getWindowRect: null,
    _setWindowRgn:  null,
    _const: {
        HWND_TOPMOST:   jsm.ctypes.voidptr_t(-1),
        HWND_NOTOPMOST: jsm.ctypes.voidptr_t(-2),
        SWP_NOACTIVATE: 0x0010,
        SWP_NOMOVE:     0x0002,
        SWP_NOSIZE:     0x0001,
    },

    _gdi32:              null,
    _createRoundRectRgn: null,

    _init: function() {
        this._user32 = jsm.ctypes.open("user32");

        this._findWindow = this._user32.declare("FindWindowW",
            jsm.ctypes.winapi_abi,
            jsm.ctypes.voidptr_t,    //HWND
            jsm.ctypes.jschar.ptr,   //LPCTSTR
            jsm.ctypes.jschar.ptr);  //LPCTSTR
        this._setWindowPos = this._user32.declare("SetWindowPos",
            jsm.ctypes.winapi_abi,
            jsm.ctypes.bool,
            jsm.ctypes.voidptr_t,    //HWND
            jsm.ctypes.voidptr_t,    //HWND
            jsm.ctypes.int,
            jsm.ctypes.int,
            jsm.ctypes.int,
            jsm.ctypes.int,
            jsm.ctypes.unsigned_int);
        this._getWindowRect = this._user32.declare("GetWindowRect",
            jsm.ctypes.winapi_abi,
            jsm.ctypes.bool,
            jsm.ctypes.voidptr_t,    //HWND
            RECT.ptr);               //LPRECT
        this._setWindowRgn = this._user32.declare("SetWindowRgn",
            jsm.ctypes.winapi_abi,
            jsm.ctypes.int,
            jsm.ctypes.voidptr_t,    //HWND
            jsm.ctypes.voidptr_t,    //HRGN
            jsm.ctypes.bool);


        this._gdi32 = jsm.ctypes.open("gdi32");

        this._createRoundRectRgn = this._gdi32.declare("CreateRoundRectRgn",
            jsm.ctypes.winapi_abi,
            jsm.ctypes.voidptr_t,    //HRGN
            jsm.ctypes.int,
            jsm.ctypes.int,
            jsm.ctypes.int,
            jsm.ctypes.int,
            jsm.ctypes.int,
            jsm.ctypes.int);


        this._getLastError = function() {
            return jsm.ctypes.winLastError || 0;
        }
    },
    _close: function() {
        this._user32.close();
        this._gdi32.close();
    },
    _error: function(msg) {
        Cu.reportError([msg, this._getLastError()].join(': '));
        this._close();
        return false;
    },

    setTopMost: function(winName, winOnTop) {
        this._init();
        var handle = this._findWindow("MozillaWindowClass", winName.trim());
        if (handle.isNull()) {
            return this._error('FindWindow');
        }
        if (!this._setWindowPos(handle,
                winOnTop ? this._const.HWND_TOPMOST
                         : this._const.HWND_NOTOPMOST,
                0, 0, 0, 0,
                this._const.SWP_NOACTIVATE |
                this._const.SWP_NOMOVE |
                this._const.SWP_NOSIZE)) {
            return this._error('SetWindowPos');
        }
        this._close();
        return true;
    },
    setRoundWindow: function(winName, winHandle, cornerWidth, cornerHeight) {
        this._init();
        var handle = winHandle ||
                     this._findWindow("MozillaWindowClass", winName.trim());
        if (handle.isNull()) {
            return this._error('FindWindow');
        }
        var rect = RECT();
        if (!this._getWindowRect(handle, rect.address())) {
            return this._error('GetWindowRect');
        }
        var width = rect.right - rect.left;
        var height = rect.bottom - rect.top;
        var region = this._createRoundRectRgn(0, 0, width, height,
                         cornerWidth, cornerHeight);
        if (!region) {
            return this._error('CreateRoundRectRgn');
        }
        if (!this._setWindowRgn(handle, region, true)) {
            return this._error('SetWindowRgn');
        }
        this._close();
        return handle;
    }
};

function _getBaseWindow(win) {
    return win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
            .getInterface(Components.interfaces.nsIWebNavigation)
            .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
            .treeOwner
            .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
            .getInterface(Components.interfaces.nsIXULWindow)
            .docShell
            .QueryInterface(Components.interfaces.nsIBaseWindow);
}

var windowHelper = {
    /**
     * Set window border radius
     * @param win
     *     window object
     * @param width
     * @param height
     * @param name
     *     The name of window, is used for finding window handler.
     */
    setRoundRgn: function(win, width, height, name) {
        // if os is winnt, then use js-ctype
        if (jsm.Services.appinfo.OS == "WINNT") {
            win.setTimeout(function() {
                var winHandle = ctypesWindowHelper.setRoundWindow(name, false, width, height);
                win.onresize = function() {
                    ctypesWindowHelper.setRoundWindow(null, winHandle, width, height);
                }
            }, 100);

        }
    },

    setTopMost: function(win, name, onTop) {
        if (jsm.Services.appinfo.OS == "WINNT") {
            ctypesWindowHelper.setTopMost(name, onTop);
        }
    }
}
