pragma solidity ^0.4.15;

contract MetaHomepage {
    /// Buy is emitted when an land unit is reserved.
    event Buy(
        uint indexed idx,
        address owner,
        uint x,
        uint y,
        uint width,
        uint height
    );

    /// Publish is emitted whenever the contents of an land is changed.
    event Publish(
        uint indexed idx,
        string link,
        string image,
        string title,
        bool NSFW
    );

    /// SetLandOwner is emitted whenever the ownership of an land is transfered
    event SetLandOwner(
        uint indexed idx,
        address from,
        address to
    );

    /// Price is 1 Meta divided by 1,000,000 pixels
    
    uint public constant weiPixelPrice = 10000000000000000;
    uint public constant weiPixelPriceOwner = 0;
    


    /// Each grid cell represents 100 pixels (10x10).
    uint public constant pixelsPerCell = 100;

    bool[100][100] public grid;

    /// contractOwner can withdraw the funds and override NSFW status of land units.
    address contractOwner;

    /// withdrawWallet is the fixed destination of funds to withdraw. It is
    /// separate from contractOwner to allow for a cold storage destination.
    address withdrawWallet;

    struct Land {
        address owner;
        uint x;
        uint y;
        uint width;
        uint height;
        string link;
        string image;
        string title;

        /// NSFW is whether the land is suitable for people of all
        /// ages and workplaces.
        bool NSFW;
        /// forceNSFW can be set by owner.
        bool forceNSFW;
    }

    /// lands are stored in an array, the id of an land is its index in this array.
    Land[] public lands;

    function MetaHomepage(address _contractOwner, address _withdrawWallet) {
        require(_contractOwner != address(0));
        require(_withdrawWallet != address(0));

        contractOwner = _contractOwner;
        withdrawWallet = _withdrawWallet;
    }

    /// getLandsLength tells you how many lands there are
    function getLandsLength() constant returns (uint) {
        return lands.length;
    }

    /// Lands must be purchased in 10x10 pixel blocks.
    /// Each coordinate represents 10 pixels. That is,
    ///   _x=5, _y=10, _width=3, _height=3
    /// Represents a 30x30 pixel land at coordinates (50, 100)
    function buy(uint _x, uint _y, uint _width, uint _height) payable returns (uint idx) {
        uint cost = _width * _height * pixelsPerCell * weiPixelPrice;
        if(msg.sender == contractOwner){
             cost = weiPixelPriceOwner;
        }
        
        require(cost >= 0);
        require(msg.value >= cost);

        // Loop over relevant grid entries
        for(uint i=0; i<_width; i++) {
            for(uint j=0; j<_height; j++) {
                if (grid[_x+i][_y+j]) {
                    // Already taken, undo.
                    revert();
                }
                grid[_x+i][_y+j] = true;
            }
        }

        // We reserved space in the grid, now make a placeholder entry.
        Land memory land = Land(msg.sender, _x, _y, _width, _height, "", "", "", false, false);
        idx = lands.push(land) - 1;
        Buy(idx, msg.sender, _x, _y, _width, _height);
        return idx;
    }

    /// Publish allows for setting the link, image, and NSFW status for the land
    /// unit that is identified by the idx which was returned during the buy step.
    /// The link and image must be full web3-recognizeable URLs, such as:
    ///  - bzz://a5c10851ef054c268a2438f10a21f6efe3dc3dcdcc2ea0e6a1a7a38bf8c91e23
    ///  - bzz://mydomain.eth/land.png
    ///  - https://cdn.mydomain.com/land.png
    /// Images should be valid PNG.
    function publish(uint _idx, string _link, string _image, string _title, bool _NSFW) {
        Land storage land = lands[_idx];
        require(msg.sender == land.owner);
        land.link = _link;
        land.image = _image;
        land.title = _title;
        land.NSFW = _NSFW;

        Publish(_idx, land.link, land.image, land.title, land.NSFW || land.forceNSFW);
    }

    /// setLandOwner changes the owner of an land unit
    function setLandOwner(uint _idx, address _newOwner) {
        Land storage land = lands[_idx];
        require(msg.sender == land.owner);
        land.owner = _newOwner;

        SetLandOwner(_idx, msg.sender, _newOwner);
    }

    /// forceNSFW allows the owner to override the NSFW status for a specific Land unit.
    function forceNSFW(uint _idx, bool _NSFW) {
        require(msg.sender == contractOwner);
        Land storage land = lands[_idx];
        land.forceNSFW = _NSFW;

        Publish(_idx, land.link, land.image, land.title, land.NSFW || land.forceNSFW);
    }

    /// withdraw allows the owner to transfer out the balance of the contract.
    function withdraw() {
        require(msg.sender == contractOwner);
        withdrawWallet.transfer(this.balance);
    }
}