contract SettlersOfCryptan is ERC721Enumerable, ReentrancyGuard, Ownable {
    bool public claimIsActive = false;
    uint256 public landIndex = 1;
    uint256 public ownerIndex = 9001;
    uint256 public constant landPrice = 80000000000000000; //0.08 ETH
    uint256 public maxLandClaim = 40;

    //pasture = wool, fields = grain, forest = lumber, hills = brick, mountains = ore
    string[] private land = [
        "Pasture",
        "Fields",
        "Forest",
        "Hills",
        "Mountains",
        "Desert"
    ];

    //pasture = wool, fields = grain, forest = lumber, hills = brick, mountains = ore
    string[] private resource = [
        "Wool",
        "Grain",
        "Lumber",
        "Brick",
        "Ore",
        "None"
    ];

    function random(string memory input) internal pure returns (uint256) {
        return uint256(keccak256(abi.encodePacked(input)));
    }

    //keeping the same probablity of board game for number distribution - 18 tiles, 2 each of 3-11(no 7), 1 each of 2 & 12
    function getLuckyNumber(uint256 tokenId) public view returns (uint256) {
        string memory thisLand = getLandType(tokenId);
        if (
            keccak256(abi.encodePacked(thisLand)) !=
            keccak256(abi.encodePacked("Desert"))
        ) {
            uint256 rand = (random(
                string(abi.encodePacked("WAGMI", toString(tokenId)))
            ) % 9) + 3;
            if (rand != 7) {
                return rand;
            } else {
                rand =
                    random(
                        string(abi.encodePacked("IYKYK", toString(tokenId)))
                    ) %
                    2;
                return rand == 0 ? 2 : 12;
            }
        } else {
            return 7;
        }
    }

    function getLuckyNumberSVG(uint256 tokenId)
        internal
        view
        returns (string memory)
    {
        string[6] memory parts;
        uint256 num = getLuckyNumber(tokenId);

        parts[0] = '<circle style="fill:#E6E6E6;" cx="250" cy="250" r="50"/><g style="fill:';
        parts[2] = ';font-family:serif;font-size:60px;"><text x="250" y="262" text-anchor="middle">';
        parts[3] = toString(num);
        parts[4] = "</text>";

        if (num == 6 || num == 8) {
            parts[1] = "#dc143c";
            parts[5] = '<circle cx="226" cy="275" r="4"/><circle cx="238" cy="275" r="4"/><circle cx="250" cy="275" r="4"/><circle cx="262" cy="275" r="4"/><circle cx="274" cy="275" r="4"/></g>';
        } else if (num == 5 || num == 9) {
            parts[1] = "#000";
            parts[5] = '<circle cx="232" cy="275" r="4"/><circle cx="244" cy="275" r="4"/><circle cx="256" cy="275" r="4"/><circle cx="268" cy="275" r="4"/></g>';
        } else if (num == 4 || num == 10) {
            parts[1] = "#000";
            parts[5] = '<circle cx="238" cy="275" r="4"/><circle cx="250" cy="275" r="4"/><circle cx="262" cy="275" r="4"/></g>';
        } else if (num == 3 || num == 11) {
            parts[1] = "#000";
            parts[5] = '<circle cx="244" cy="275" r="4"/><circle cx="256" cy="275" r="4"/></g>';
        } else {
            parts[1] = "#000";
            parts[5] = '<circle cx="250" cy="275" r="4"/></g>';
        }

        string memory svgString = string(
            abi.encodePacked(
                parts[0],
                parts[1],
                parts[2],
                parts[3],
                parts[4],
                parts[5]
            )
        );

        return svgString;
    }

    //keeping the same probability of board game for land distribution, pasture = 4, fields = 4, forest = 4, hills = 3, mountains = 3, desert = 1
    function getLandId(uint256 tokenId) internal pure returns (uint256) {
        uint256 rand = random(
            string(abi.encodePacked("HODL", toString(tokenId)))
        ) % 19;
        if (rand < 4) {
            return 0;
        } else if (rand < 8) {
            return 1;
        } else if (rand < 12) {
            return 2;
        } else if (rand < 15) {
            return 3;
        } else if (rand < 18) {
            return 4;
        } else {
            return 5;
        }
    }

    function getLandType(uint256 tokenId) public view returns (string memory) {
        return land[getLandId(tokenId)];
    }

    function getLandResource(uint256 tokenId) public view returns (string memory) {
        return resource[getLandId(tokenId)];
    }

    function getLandSVG(uint256 tokenId) internal pure returns (string memory) {
        uint256 rand = random(
            string(abi.encodePacked("HODL", toString(tokenId)))
        ) % 19;
        if (rand < 4) {
            return
                '<polygon style="fill:#77dd77;" points="405,339.6 249.8,429.2 94.6,339.6 94.6,160.4 249.8,70.8 405,160.4"/><path style="fill:#39B54A;" d="M229.4,305h175.8V194.5C405.2,194.5,213,209,229.4,305z"/><path style="fill:#009245;" d="M336,319H94.6v-87.5C94.6,231.5,299,240.2,336,319z"/><g style="stroke:#000000;stroke-width:3;stroke-linecap:round;stroke-miterlimit:10;"><line x1="243.3" y1="371.9" x2="243.3" y2="360.9"/><line x1="250" y1="369.4" x2="250" y2="358.4"/><line x1="266.9" y1="370.9" x2="266.9" y2="359.9"/><line x1="274.2" y1="372.9" x2="274.2" y2="361.9"/></g><g style="fill:#FFFFFF;"><circle class="st11" cx="241.7" cy="341.8" r="12.4"/><ellipse cx="258.3" cy="346.1" rx="21.6" ry="17.3"/><ellipse cx="270.6" cy="352.1" rx="12" ry="11"/><circle cx="243.3" cy="353.8" r="10.5"/><circle cx="276.2" cy="339" r="9.5"/></g><circle style="fill:#000000;" cx="284.8" cy="331.8" r="6"/><line style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:round;stroke-miterlimit:10;" x1="284.8" y1="334.5" x2="288.7" y2="337.1"/><g style="fill:#FFFFFF;"><ellipse transform="matrix(0.9419 0.3358 -0.3358 0.9419 127.8728 -75.3625)" cx="281.9" cy="332.1" rx="1" ry="2.6"/><circle cx="287.5" cy="330.7" r="1.1"/></g>';
        } else if (rand < 8) {
            return
                '<polygon style="fill:#fcc200;" points="405,339.6 249.8,429.2 94.6,339.6 94.6,160.4 249.8,70.8 405,160.4"/><g style="fill:#DAA520;"><rect x="249.8" y="182.5" width="155.2" height="99.6"/><rect x="94.6" y="160.4" width="98.4" height="163.5"/></g><g style="fill:none;stroke:#B8860B;stroke-width:3;stroke-linecap:round;stroke-miterlimit:10;"><line class="st13" x1="232.4" y1="329.3" x2="232.4" y2="383.2"/><polyline points="243.2,329.3 232.4,340.1 221.6,329.3"/><polyline points="243.2,340.1 232.4,350.9 221.6,340.1"/><polyline points="243.2,350.9 232.4,361.6 221.6,350.9"/><polyline points="243.2,323.9 243.2,361.6 232.4,372.4 221.6,361.6 221.6,323.9"/><line x1="268" y1="337" x2="268" y2="383.6"/><polyline points="277.3,337 268,346.3 258.7,337"/><polyline points="277.3,346.3 268,355.6 258.7,346.3"/><polyline points="277.3,355.6 268,364.9 258.7,355.6"/><polyline points="277.3,332.4 277.3,364.9 268,374.3 258.7,364.9 258.7,332.4"/></g><g style="fill:none;stroke:#F0DC82;stroke-miterlimit:10;"><line x1="258.7" y1="194.8" x2="404.3" y2="194.8"/><line x1="258.7" y1="209.8" x2="404.3" y2="209.8"/><line x1="258.7" y1="224.8" x2="404.3" y2="224.8"/><line x1="258.7" y1="239.8" x2="404.3" y2="239.8"/><line x1="258.7" y1="254.8" x2="404.3" y2="254.8"/><line x1="258.7" y1="269.8" x2="404.3" y2="269.8"/></g>';
        } else if (rand < 12) {
            return
                '<polygon style="fill:#3b7a57;" points="405,339.6 249.8,429.2 94.6,339.6 94.6,160.4 249.8,70.8 405,160.4"/><g style="fill:none;stroke:#754C24;stroke-width:18;stroke-miterlimit:10;"><line x1="227.7" y1="357.8" x2="263" y2="348.8"/><line x1="236.3" y1="342.5" x2="271.7" y2="333.5"/><line x1="245" y1="357.8" x2="280.3" y2="348.8"/></g><g style="fill:#754C24;"><circle cx="280.3" cy="348.8" r="9"/><circle cx="271.7" cy="333.5" r="9"/></g><g style="fill:#C69C6D;"><circle cx="227.7" cy="357.8" r="9"/><circle cx="236.3" cy="342.5" r="9"/><circle cx="245" cy="357.8" r="9"/></g><g style="fill:none;stroke:#8C6239;stroke-miterlimit:10;"><circle cx="227.7" cy="357.8" r="6"/><circle cx="227.7" cy="357.8" r="3"/><circle cx="236.3" cy="342.5" r="6"/><circle cx="236.3" cy="342.5" r="3"/><circle cx="245" cy="357.8" r="6"/><circle cx="245" cy="357.8" r="3"/></g><g style="fill:none;stroke:#754C24;stroke-width:10;stroke-miterlimit:10;"><line class="st20" x1="195.8" y1="228.7" x2="195.8" y2="203.2"/><line class="st20" x1="367.7" y1="271.1" x2="367.7" y2="242.7"/><line class="st20" x1="133.1" y1="246.2" x2="133.1" y2="220.5"/><line class="st20" x1="321.7" y1="234.7" x2="321.7" y2="211.6"/><line class="st20" x1="166.9" y1="269.4" x2="166.9" y2="237"/></g><g style="fill:#77DD77;"><polygon points="173,214.4 195.8,144.6 218.7,214.4"/><polygon points="342.4,255.1 367.7,177.6 393.1,255.1"/></g><polygon style="fill:#006400;" points="110.2,231.8 133.1,161.5 156.1,231.8"/><g style="fill:#49B86E;"><polygon points="301.1,221.7 321.7,158.6 342.4,221.7"/><polygon points="137.9,251.1 166.9,162.6 195.8,251.1"/></g>';
        } else if (rand < 15) {
            return
                '<polygon style="fill:#B73239;" points="405,339.6 249.8,429.2 94.6,339.6 94.6,160.4 249.8,70.8 405,160.4"/><g style="fill:#FF7066;"><path d="M156.3,158.3l-9.4,9.4v10.1h-3.8l-9.4,9.4v53.3L117,277.8l43.4,10.2V158.3H156.3z"/><polygon points="297,191.4 297,270 323.6,270 316.9,191.4"/></g><g style="fill:#FF5347;"><path d="M225.2,277.8l-16.8-37.5v-34.5h-21.4v-38.2l-9.4-9.4h-17.3V288L225.2,277.8z"/><path d="M364.3,222.9v-57.3h-47.4V270l62.5-13.3L364.3,222.9z"/></g><g style="fill:#b22222;stroke:#FF7066;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:10;"><polygon points="225,342 225,369 252,378 252,351"/><polygon points="252,351 297,324 297,351 252,378"/><polygon style="fill:#FF7066;" points="225,342 252,351 297,324 270,315"/></g>';
        } else if (rand < 18) {
            return
                '<polygon style="fill:#bebebe;" points="405,339.6 249.8,429.2 94.6,339.6 94.6,160.4 249.8,70.8 405,160.4"/><g style="fill:#100C08;"><polygon points="229.3,362.4 225.5,355.8 227.4,351.2 237.3,349.1 242.9,355.8 241.5,359.8"/><polygon points="230.1,346.3 226.3,342.3 231.2,336.3 239.2,334.2 242.1,341.1 239.6,346.3"/><polygon points="251.8,358 245.4,340.5 257.6,322.9 280.5,331.1 282.5,353.6 275.8,358"/></g><polygon style="fill:#A0A0A0;" points="263.9,354.6 271,348 272.2,342.4 266.7,330.2 276.3,340.5 274.2,354.3"/><g style="fill:#36454F;"><polygon points="105.7,253.3 165.3,152.3 224.9,253.3"/><polygon points="165.3,236.5 210.9,163.5 256.4,236.5"/><polygon points="259.8,239.3 303,172.3 346.2,239.3"/><polygon points="279.9,253.3 338.9,150.2 397.9,253.3"/></g>';
        } else {
            return
                '<polygon style="fill:#f3e5ab;" points="405,339.6 249.8,429.2 94.6,339.6 94.6,160.4 249.8,70.8 405,160.4"/><line style="fill:none;stroke:#009245;stroke-width:6;stroke-linecap:round;stroke-miterlimit:10;" x1="167.5" y1="219.8" x2="167.5" y2="247.3"/><g style="fill:none;stroke:#009245;stroke-width:5;stroke-linecap:round;stroke-miterlimit:10;"><path d="M166.4,228.4c-4.1,0-7.4-3.8-7.4-8.5"/><path d="M168.7,236c4.3,0,7.7-2.4,7.7-5.3"/></g><path style="fill:#FFD039;" d="M315,186c-15,51.5-220.4,67-220.4,67v86.6l155.2,89.6L405,339.6c-14.8-19.7-36.5-99.6-36.5-99.6L315,186z"/><path style="fill:#EAB932;" d="M405,339.6l-135.6,78.3c53-109.5-2.4-85.4,35.1-128.9c49-50,10.9-102.7,10.5-103c0.4,0.1,90,64,90,64V339.6z"/>';
        }
    }

    /**
     * @dev Hash to metadata function
     */
    function hashToMetadata(uint256 tokenId)
        public
        view
        returns (string memory)
    {
        string memory metadataString;

        metadataString = string(
            abi.encodePacked(
                '{"trait_type": "Land Type",',
                '"value":"',
                getLandType(tokenId),
                '"},',
                '{"trait_type":" Lucky Number",',
                '"value":"',
                toString(getLuckyNumber(tokenId)),
                '"},',
                '{"trait_type":" Resource",',
                '"value":"',
                getLandResource(tokenId),
                '"}'
            )
        );

        return string(abi.encodePacked("[", metadataString, "]"));
    }

    function tokenURI(uint256 tokenId)
        public
        view
        override
        returns (string memory)
    {
        string[4] memory parts;

        parts[
            0
        ] = '<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 500 500"><polygon style="fill:#C7B299;" points="423.2,350 250,450 76.8,350 76.8,150 250,50 423.2,150"/>';

        parts[1] = getLandSVG(tokenId);

        if (
            keccak256(abi.encodePacked(getLandType(tokenId))) !=
            keccak256(abi.encodePacked("Desert"))
        ) {
            parts[2] = getLuckyNumberSVG(tokenId);
        } else {
            parts[2] = "";
        }

        parts[3] = "</svg>";

        string memory output = string(
            abi.encodePacked(parts[0], parts[1], parts[2], parts[3])
        );

        string memory json = Base64.encode(
            bytes(
                string(
                    abi.encodePacked(
                        '{"name": "Settlers of Cryptan - Land #',
                        toString(tokenId),
                        '", "description": "Settlers of Cryptan Land is the genesis collection of 10,000 pieces of land that are available as part of a 100% on-chain settlers game experience with all metadata, images and game mechanics stored on the ethereum blockchain. Feel free to play along or use in any way you want.", "image": "data:image/svg+xml;base64,',
                        Base64.encode(bytes(output)),
                        '","attributes": ',
                        hashToMetadata(tokenId),
                        "}"
                    )
                )
            )
        );
        output = string(
            abi.encodePacked("data:application/json;base64,", json)
        );

        return output;
    }

    /*
     * Pause claim if active, make active if paused
     */
    function flipClaimState() public onlyOwner {
        claimIsActive = !claimIsActive;
    }

    // Land #1 to #9000 are claimable by anyone. Land #9001 to #10000 will be distributed by the contract deployer through giveaways, rewards and other means.

    function claim(uint256 amountOfLand) public payable {
        require(claimIsActive, "The game must be on to claim land!");
        require(
            amountOfLand <= maxLandClaim,
            "Can only claim up to 40 pieces of land at a time"
        );
        require(
            (landPrice * amountOfLand) <= msg.value,
            "Ether value sent is not correct"
        );
        require(landIndex < 9001, "All land has been claimed");
        if ((landIndex + amountOfLand) > 9001) {
            amountOfLand = 9001 - landIndex;
        }
        for (uint256 i = 0; i < amountOfLand; i++) {
            _safeMint(_msgSender(), landIndex + i);
        }
        landIndex = landIndex + amountOfLand;
    }

    function ownerClaim(uint256 amountOfLand) public nonReentrant onlyOwner {
        require(
            ownerIndex > 9000 && ownerIndex < 10001,
            "All land has been claimed"
        );
        if ((ownerIndex + amountOfLand) > 10001) {
            amountOfLand = 10001 - ownerIndex;
        }
        for (uint256 i = 0; i < amountOfLand; i++) {
            _safeMint(owner(), ownerIndex + i);
        }
        ownerIndex = ownerIndex + amountOfLand;
    }

    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT license
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    function withdraw() public onlyOwner {
        require(payable(msg.sender).send(address(this).balance));
    }

    constructor() ERC721("Settlers of Cryptan - Land", "SOCL") Ownable() {}
}
function getLandId(uint256 tokenId) internal pure returns (uint256) {
    uint256 rand = random(
        string(abi.encodePacked("HODL", toString(tokenId)))
    ) % 19;
    if (rand < 4) {
        return 0;
    } else if (rand < 8) {
        return 1;
    } else if (rand < 12) {
        return 2;
    } else if (rand < 15) {
        return 3;
    } else if (rand < 18) {
        return 4;
    } else {
        return 5;
    }
}

//keeping the same probability of board game for land distribution, pasture = 4, fields = 4, forest = 4, hills = 3, mountains = 3, desert = 1