// http://www.xfree86.org/current/AppleWM.3.html
// http://opensource.apple.com/source/X11server/X11server-106.3/Xquartz/xorg-server-1.10.2/hw/xquartz/applewm.c
// /usr/X11/include/X11/extensions/applewm.h
var x11 = Require('x11/core/x11');
var xutil = Require('x11/core/xutil');
// TODO: move to templates
/*
#define X_AppleWMFrameGetRect           1
#define X_AppleWMFrameHitTest           2
#define X_AppleWMFrameDraw              3
#define X_AppleWMDisableUpdate          4
#define X_AppleWMReenableUpdate         5
#define X_AppleWMSetWindowMenuCheck     7
#define X_AppleWMSetWindowMenu          11
#define X_AppleWMSendPSN                12
#define X_AppleWMAttachTransient        13
*/
exports.requireExt = function(display, callback)
{
    var X = display.client;
    X.QueryExtension('Apple-WM', function(err, ext) {
        if (!ext.present)
            callback(new Error('extension not available'));
        ext.QueryVersion = function(cb)
        {
            X.seq_num++;
            X.pack_stream.pack('CCS', [ext.majorOpcode, 0, 1]);
            X.replies[X.seq_num] = [
                function(buf, opt) {
                    var res = buf.unpack('SSL');
                    return res;
                },
                cb
            ];
            X.pack_stream.flush();
        }
        ext.FrameRect = {
            Titlebar: 1,
            Tracking: 2,
            Growbox: 3
        };
        ext.FrameGetRect = function(frame_class, frame_rect, ix, iy, iw, ih, ox, oy, ow, oh, cb)
        {
            X.seq_num++;
            X.pack_stream.pack('CCSSSSSSSSSSS', [ext.majorOpcode, 1, 6, frame_class, frame_rect, ix, iy, iw, ih, ox, oy, ow, oh, cb]);
            X.replies[X.seq_num] = [
                function(buf, opt) {
                    var res = buf.unpack('SSSS');
                    return {
                        x: res[0],
                        y: res[1],
                        w: res[2],
                        h: res[3]
                    };
                },
                cb
            ];
            X.pack_stream.flush();
        }
        ext.FrameHitTest = function(frame_class, px, py, ix, iy, iw, ih, ox, oy, ow, oh, cb)
        {
            X.seq_num++;
            X.pack_stream.pack('CCSSxxSSSSSSSSSS', [ext.majorOpcode, 2, 7, frame_class, px, py, ix, iy, iw, ih, ox, oy, ow, oh]);
            X.replies[X.seq_num] = [
                function(buf, opt) {
                    var res = buf.unpack('L');
                    return res[0];
                },
                cb
            ];
            X.pack_stream.flush();
        }
// from /usr/include/Xplugin.h
        ext.FrameClass = {
            DecorLarge: 1,
            Reserved1: 2,
            Reserved2: 4,
            Reserved3: 8,
            DecorSmall: 16,
            Reserved5: 32,
            Reserved6: 64,
            Reserved8: 128,
            Managed: 1<<15,
            Transient: 1<<16,
            Stationary: 1<<17
        };
        ext.FrameAttr = {
            Active:   1,
            Urgent:   2,
            Title:    4,
            Prelight: 8,
            Shaded:  16,
            CloseBox: 0x100,
            Collapse: 0x200,
            Zoom:     0x400,
            CloseBoxClicked: 0x800,
            CollapseBoxClicked: 0x1000,
            ZoomBoxClicked: 0x2000,
            GrowBox: 0x4000
        };
        ext.FrameDraw = function(screen, window, frameClass, attr, ix, iy, iw, ih, ox, oy, ow, oh, title)
        {
            X.seq_num++;
            var titleReqWords = xutil.padded_length(title.length)/4;
            X.pack_stream.pack('CCSLLSSSSSSSSSSLp', [ext.majorOpcode, 3, 9+titleReqWords, screen, window, frameClass, attr, ix, iy, iw, ih, ox, oy, ow, oh, title.length, title]);
            X.pack_stream.flush();
        }
        ext.NotifyMask = {
            Controller: 1,
            Activation: 2,
            Pasteboard: 4,
            All: 7
        };
// TODO: decode events
/*
#define AppleWMMinimizeWindow           0
#define AppleWMZoomWindow               1
#define AppleWMCloseWindow              2
#define AppleWMBringAllToFront          3
#define AppleWMHideWindow               4
#define AppleWMHideAll                  5
#define AppleWMShowAll                  6
#define AppleWMWindowMenuItem           9
#define AppleWMWindowMenuNotify         10
#define AppleWMNextWindow               11
#define AppleWMPreviousWindow           12
#define AppleWMIsActive                 0
#define AppleWMIsInactive               1
#define AppleWMReloadPreferences        2
#define AppleWMCopyToPasteboard         0
*/
        ext.SelectInput = function(mask)
        {
            X.seq_num++;
            X.pack_stream.pack('CCSL', [ext.majorOpcode, 6, 2, mask]);
            X.pack_stream.flush();
        }
        ext.SetFrontProcess = function()
        {
            X.seq_num++;
            X.pack_stream.pack('CCS', [ext.majorOpcode, 8, 1]);
            X.pack_stream.flush();
        }
        ext.WindowLevel = {
            Normal: 0,
            Floating: 1,
            TornOff: 2,
            Dock: 3,
            Desktop: 4
        };
        ext.SetWindowLevel = function(window, level)
        {
            X.seq_num++;
            X.pack_stream.pack('CCSLL', [ext.majorOpcode, 9, 3, window, level]);
            X.pack_stream.flush();
        }
        ext.CanQuit = function(state)
        {
            X.seq_num++;
            X.pack_stream.pack('CCSCxxx', [ext.majorOpcode, 10, 2, state]);
            X.pack_stream.flush();
        }
        // shortcut is single-byte ASCII (optional, 0=no shortcut)
        // items example: [ 'item1', 'some item', ['C', 'item with C shortcut'] ]
        ext.SetWindowMenu = function(items)
        {
           var reqlen = 8;
           var extlength = 0;
           items.forEach(function(i) {
           });
        }
        // https://developer.apple.com
        //    /library/mac/documentation/Carbon/Reference/Process_Manager/Reference/reference.html#//apple_ref/doc/c_ref/ProcessSerialNumber
        ext.SendPSN = function(hi, lo)
        {
            X.seq_num++;
            X.pack_stream.pack('CCSLL', [ext.majorOpcode, 12, 3, hi, lo]);
            X.pack_stream.flush();
        }
        ext.AttachTransient = function(child, parent)
        {
            X.seq_num++;
            X.pack_stream.pack('CCSLL', [ext.majorOpcode, 13, 3, child, parent]);
            X.pack_stream.flush();
        }
        callback(null, ext);
        /*
        ext.QueryVersion(function(err, vers) {
            ext.major = vers[0];
            ext.minor = vers[1];
            ext.patch = vers[2];
            callback(null, ext);
        });
        */
        ext.events = {
            AppleWMControllerNotify: 0,
            AppleWMActivationNotify: 1,
            AppleWMPasteboardNotify: 2,
        }
        ext.EventKind = {
          Controller: {
            MinimizeWindow: 0,
            ZoomWindow: 1,
            CloseWindow: 2,
            BringAllToFront: 3,
            WideWindow: 4,
            HideAll: 5,
            ShowAll: 6,
            WindowMenuItem: 9,
            WindowMenuNotify: 10,
            NextWindow: 11,
            PreviousWindow: 12
          },
          Activation: {
            IsActive: 0,
            IsInactive:1,
            ReloadPreferences: 2
          },
          Pasteboard: {
            CopyToPasteboard: 0
          }
        };
        X.eventParsers[ext.firstEvent + ext.events.AppleWMControllerNotify] =
        X.eventParsers[ext.firstEvent + ext.events.AppleWMActivationNotify] =
        X.eventParsers[ext.firstEvent + ext.events.AppleWMPasteboardNotify] = function(type, seq, extra, code, raw)
        {
            var event = {};
            switch(type) {
                case ext.firstEvent + ext.events.AppleWMControllerNotify: event.name = 'AppleWMControllerNotify'; break;
                case ext.firstEvent + ext.events.AppleWMActivationNotify: event.name = 'AppleWMActivationNotify'; break;
                case ext.firstEvent + ext.events.AppleWMPasteboardNotify: event.name = 'AppleWMPasteboardNotify'; break;
            }
            event.type = code;
            event.time = extra;
            event.arg = raw.unpack('xxL')[0];
            return event;
        };
    });
}