/// <reference path="stampit.d.ts" />

import stampit = require('stampit');

var a = stampit().init((options) => {
    var a = options.args[0];
    this.getA = () => {
        return a;
    };
});
a(); // Object -- so far so good.
a().getA(); // "a"


var b = stampit().init(function () {
    var a = 'b';
    this.getB = function () {
        return a;
    };
});


var c = stampit.compose(a, b);
var foo = c(); // we won't throw this one away...
foo.getA(); // "a"
foo.getB(); // "b"


// Some more privileged methods, with some private data.
// Use stampit.mixIn() to make this feel declarative:
var availability = stampit().init(function () {
    var isOpen = false; // private

    return stampit.mixIn(this, {
        open: function open() {
            isOpen = true;
            return this;
        },
        close: function close() {
            isOpen = false;
            return this;
        },
        isOpen: function isOpenMethod() {
            return isOpen;
        }
    });
});

// Here's a mixin with public methods, and some refs:
var membership = stampit({
    methods: {
        members: {},
        add: function (member:any) {
            this.members[member.name] = member;
            return this;
        },
        getMember: function (name:any) {
            return this.members[name];
        }
    },
    refs: {
        members: {}
    }
});
// Let's set some defaults:
var defaults = stampit().refs({
    name: 'The Saloon',
    specials: 'Whisky, Gin, Tequila'
});

// Classical inheritance has nothing on this. No parent/child coupling. No deep inheritance hierarchies.
// Just good, clean code reusability.
var bar = stampit.compose(defaults, availability, membership);
// Note that you can override refs on instantiation:
var myBar = bar({name: 'Moe\'s'});
// Silly, but proves that everything is as it should be.
myBar.add({name: 'Homer'}).open().getMember('Homer');


var myStamp = stampit().methods({
    foo: function () {
        return 'foo';
    },
    methodOverride: function () {
        return false;
    }
}).methods({
    bar: function () {
        return 'bar'
    },
    methodOverride: function () {
        return true;
    }
});

myStamp.refs({
    foo: {bar: 'bar'},
    refsOverride: false
}).refs({
    bar: 'bar',
    refsOverride: true
});

myStamp.init(function () {
    var secret = 'foo';

    this.getSecret = function () {
        return secret;
    };
}).init(function () {
    this.a = true;
}).init({
    bar: function bar() {
        this.b = true;
    }
}, {
    baz: function baz() {
        this.c = true;
    }
});

var obj = myStamp.create();
obj.getSecret && obj.a && obj.b && obj.c; // true

var newStamp = stampit({refs: {defaultNum: 1}}).compose(myStamp);


var obj1 = stampit().methods({
    a: function () {
        return 'a';
    }
}, {
    b: function () {
        return 'b';
    }
}).create();

var obj2 = stampit().refs({
    a: 'a'
}, {
    b: 'b'
}).create();

var obj = defaults.compose(newStamp, membership, availability).create();


// The old constructor / class thing...
var Constructor = function Constructor() {
    this.thing = 'initialized';
};
Constructor.prototype.foo = function foo() {
    return 'foo';
};

// The conversion
var oldskool = stampit.convertConstructor(Constructor);

// A new stamp to compose with...
var newskool = stampit().methods({
    bar: function bar() {
        return 'bar';
    }
    // your methods here...
}).init(function () {
    this.baz = 'baz';
});

// Now you can compose those old constructors just like you could
// with any other stamp...
var myThing = stampit.compose(oldskool, newskool);

var t = myThing();

t.thing; // 'initialized',

t.foo(); // 'foo',

t.bar(); // 'bar'
