-- GFXP for Playdate (2.2.0)
-- Lib: https://github.com/ivansergeev/gfxp
-- GFXP Pattern Editor: https://dev.playdate.store/tools/gfxp/
--
-- The MIT License (MIT)
--
-- Copyright (c) 2022 Ivan Sergeev <ivansergeev@gmail.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy of
-- this software and associated documentation files (the "Software"), to deal in
-- the Software without restriction, including without limitation the rights to
-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-- the Software, and to permit persons to whom the Software is furnished to do so,
-- subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


--[[
	Example of use GFXP

	Before you begin, import "gfxp.lua" from "Source/lib" folder into the source folder of your project.
	import 'lib/gfxp'
	It is enough to do this once, for example in "main.lua"

	Then in any file with your code:

	Option 1:
		-- Declare a local variable
		local gfxp <const> = GFXP

		-- specify the name of the pattern
		gfxp.set('dot-1')

		-- or the inverted version, just add an "i" at the end. For example:
		gfxp.set('dot-1i')


	Option 2: set only

		-- Declare a local variable
		local gfxp <const> = GFXP.set

		-- then specify the name of the pattern
		gfxp('dot-1')

		-- or specify a pattern table
		gfxp({0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF})

		-- or with a mask
		gfxp({0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 128, 0, 0, 0, 0, 0, 0, 0})


	Option 3: lib only

		-- Declare a local variable
		local gfxpLib <const> = GFXP.lib

		-- then specify the name of the pattern
		playdate.graphics.setPattern(gfxpLib.gray)

		-- or
		playdate.graphics.setPattern(gfxpLib['dot-1'])

]]--

import 'CoreLibs/object'

-- ! GFXP is a global variable
GFXP = {}

GFXP.lib = {
	['white'] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
	['black'] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},

	-- Grayscale

	['lightgray'] = {0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff, 0x77},
	['lightgray-1'] = {0x77, 0x77, 0xdd, 0xdd, 0x77, 0x77, 0xdd, 0xdd},
	['lightgray-2'] = {0x77, 0x77, 0x77, 0x77, 0xdd, 0xdd, 0xdd, 0xdd},
	['gray'] = {0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa},
	['gray-1'] = {0x33, 0x33, 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc},
	['gray-2'] = {0x33, 0x33, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xcc},
	['gray-3'] = {0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa},
	['gray-4'] = {0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55},
	['gray-5'] = {0xd2, 0x5a, 0x4b, 0x69, 0x2d, 0xa5, 0xb4, 0x96},
	['darkgray'] = {0x0, 0x22, 0x0, 0x88, 0x0, 0x22, 0x0, 0x88},
	['darkgray-1'] ={0x88, 0x88, 0x22, 0x22, 0x88, 0x88, 0x22, 0x22},
	['darkgray-2'] = {0x88, 0x88, 0x88, 0x88, 0x22, 0x22, 0x22, 0x22},

	-- Dots

	['dot-1'] = {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
	['dot-2'] = {0x7f, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff},
	['dot-3'] = {0x3f, 0x3f, 0xff, 0xff, 0xf3, 0xf3, 0xff, 0xff},
	['dot-4'] = {0x66, 0xff, 0xff, 0x66, 0x66, 0xff, 0xff, 0x66},
	['dot-5'] = {0x1f, 0x5f, 0x1f, 0xff, 0xf1, 0xf5, 0xf1, 0xff},
	['dot-6'] = {0xf, 0x6f, 0x6f, 0xf, 0xf0, 0xf6, 0xf6, 0xf0},
	['dot-7'] = {0xff, 0xff, 0xe7, 0xdb, 0xdb, 0xe7, 0xff, 0xff},
	['dot-8'] = {0xaa, 0xaa, 0x55, 0x55, 0xba, 0xba, 0x55, 0x55},
	['dot-9'] = {0xab, 0xab, 0x55, 0x55, 0xba, 0xba, 0x55, 0x55},
	['dot-10'] = {0x55, 0xaa, 0x41, 0x9c, 0x5d, 0x9c, 0x41, 0xaa},
	['dot-11'] = {0x9f, 0x6f, 0x6f, 0x9f, 0xf9, 0xf6, 0xf6, 0xf9},
	['dot-12'] = {0xff, 0xe3, 0xdd, 0xbe, 0xbe, 0xbe, 0xdd, 0xe3},
	['dot-13'] = {0xff, 0xe3, 0xc1, 0x80, 0x80, 0x80, 0xc1, 0xe3},
	['dot-14'] = {0xff, 0xe7, 0xc3, 0x99, 0x99, 0xc3, 0xe7, 0xff},
	['dot-15'] = {0xbb, 0xf5, 0xf5, 0xf5, 0xb5, 0x5b, 0x5f, 0x5f},
	['dot-16'] = {0xbd, 0x5a, 0xa5, 0xdb, 0xdb, 0xa5, 0x5a, 0xbd},
	['dot-17'] = {0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5, 0x5a},
	['dot-18'] = {0x7F, 0xB6, 0x6B, 0xF7, 0xDF, 0xAD, 0xDA, 0xFD},

	-- Crosses

	['cross-1'] = {0xff, 0xff, 0xff, 0x77, 0xaf, 0xdf, 0xaf, 0x77},
	['cross-2'] = {0xff, 0xbe, 0xdd, 0xeb, 0xf7, 0xeb, 0xdd, 0xbe},
	['cross-3'] = {0x55, 0xaa, 0x55, 0xbe, 0x5d, 0xbe, 0x55, 0xaa},
	['cross-4'] = {0xff, 0xdd, 0xaa, 0xd5, 0xeb, 0xd5, 0xaa, 0xdd},
	['cross-5'] = {0xfe, 0x38, 0xfe, 0xee, 0xef, 0x83, 0xef, 0xee},


	-- Vertical Lines

	['vline-1'] = {0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f},
	['vline-2'] = {0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77},
	['vline-3'] = {0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d},
	['vline-4'] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55},
	['vline-5'] = {0xf7, 0xf7, 0xf7, 0xf7, 0x7f, 0x7f, 0x7f, 0x7f},

	-- Horizontal Lines

	['hline-1'] = {0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
	['hline-2'] = {0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff},
	['hline-3'] = {0x0, 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0xff},
	['hline-4'] = {0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff},
	['hline-5'] = {0xff, 0x14, 0xff, 0xa2, 0xff, 0x14, 0xff, 0xa2},
	['hline-6'] = {0xf, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff},

	 -- Diagonal Lines

	['dline-1'] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f},
	['dline-2'] = {0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe},
	['dline-3'] = {0x77, 0xbb, 0xdd, 0xee, 0x77, 0xbb, 0xdd, 0xfe},
	['dline-4'] = {0xff, 0xff, 0xf7, 0xef, 0xdf, 0xbf, 0x7f, 0xff},
	['dline-5'] = {0xfc, 0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9},
	['dline-6'] = {0xf8, 0x7c, 0x3e, 0x1f, 0x8f, 0xc7, 0xe3, 0xf1},
	['dline-7'] = {0xee, 0xdd, 0xbb, 0x77, 0xee, 0xdd, 0xbb, 0x77},
	['dline-8'] = {0x77, 0xbb, 0xdd, 0xee, 0x77, 0xbb, 0xdd, 0xee},

	-- Waves

	['wave-1'] = {0xbb, 0xdd, 0xee, 0x77, 0xee, 0xdd, 0xbb, 0x77},
	['wave-2'] = {0xb7, 0x7b, 0xfc, 0xcf, 0xb7, 0x7b, 0xfc, 0xcf},
	['wave-3'] = {0xe7, 0xdb, 0xdb, 0xdb, 0xdb, 0xbd, 0x7e, 0xff},

	-- Grid

	['grid-1'] = {0xaa, 0x77, 0xaa, 0xdd, 0xaa, 0x77, 0xaa, 0xdd},
	['grid-2'] = {0x0, 0x77, 0x77, 0x77, 0x0, 0x77, 0x77, 0x77},
	['grid-3'] = {0x0, 0x6d, 0x6d, 0x0, 0x6d, 0x6d, 0x0, 0x6d},
	['grid-4'] = {0xe7, 0xdb, 0xbd, 0x7e, 0x7e, 0xbd, 0xdb, 0xe7},
	['grid-5'] = {0xff, 0xaa, 0xd5, 0xaa, 0xd5, 0xaa, 0xd5, 0xaa},
	['grid-6'] = {0x0, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f},

	-- Rect

	['rect-1'] = {0xff, 0x80, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0x80},
	['rect-2'] = {0xff, 0x81, 0xbd, 0xbd, 0xbd, 0xbd, 0x81, 0xff},
	['rect-3'] = {0xff, 0x20, 0xaf, 0xaf, 0xaf, 0xaf, 0x20, 0xff},

	-- Bricks

	['brick-1'] = {0x0, 0xdf, 0xdf, 0xdf, 0x0, 0xfd, 0xfd, 0xfd},
	['brick-2'] = {0x0, 0x0, 0xcf, 0xcf, 0x0, 0x0, 0xfc, 0xfc},
	['brick-3'] = {0x0, 0x77, 0x0, 0xdd, 0x0, 0x77, 0x0, 0xdd},
	['brick-4'] = {0x7e, 0xbd, 0xdb, 0xe7, 0xf7, 0xfb, 0xfd, 0xfe},
	['brick-5'] = {0x7e, 0xbd, 0xdb, 0xe7, 0xef, 0xdf, 0xbf, 0x7f},
	['brick-6'] = {0x55, 0xbb, 0xdd, 0xee, 0x55, 0xbb, 0xdd, 0xee},
	['brick-7'] = {0xaa, 0xdd, 0xbb, 0x77, 0xaa, 0xdd, 0xbb, 0x77},
	['brick-8'] = {0x5f, 0xae, 0x57, 0xab, 0xd5, 0xea, 0xf5, 0xbb},
	['brick-9'] = {0xfa, 0x75, 0xea, 0xd5, 0xab, 0x57, 0xaf, 0xdd},
	['brick-10'] = {0x5f, 0xee, 0x77, 0xbb, 0xdd, 0xee, 0xf5, 0xbb},
	['brick-11'] = {0xfa, 0x77, 0xee, 0xdd, 0xbb, 0x77, 0xaf, 0xdd},

	-- Flakes

	['flake-1'] = {0x7e, 0xbd, 0xc3, 0xfb, 0xfb, 0xfb, 0xfd, 0xfe},
	['flake-2'] = {0x7e, 0xbd, 0xc3, 0xdf, 0xdf, 0xdf, 0xbf, 0x7f},
	['flake-3'] = {0xfe, 0x3d, 0xc3, 0xfb, 0xfb, 0xfb, 0xfd, 0xfd},
	['flake-4'] = {0x7f, 0xbc, 0xc3, 0xdf, 0xdf, 0xdf, 0xbf, 0xbf},
	['flake-5'] = {0x7d, 0xbb, 0xcb, 0xf7, 0xcb, 0xbb, 0x7d, 0xfe},
	['flake-6'] = {0xe1, 0xde, 0xbe, 0x7f, 0x7f, 0x7f, 0x9f, 0xef},
	['flake-7'] = {0x7e, 0xbd, 0xbb, 0xb7, 0x8f, 0xef, 0xe1, 0xfe},
	['flake-8'] = {0xf7, 0xf7, 0xeb, 0x9c, 0x7f, 0x7f, 0xbe, 0xc9},
	['flake-9'] = {0xfe, 0x3d, 0xcb, 0xf7, 0xfb, 0xfb, 0xfd, 0xfd},
	['flake-10'] = {0x7f, 0xae, 0xd5, 0xbb, 0xdf, 0xef, 0xdf, 0xbf},

	-- Decor

	['decor-1'] = {0x1f, 0x37, 0x73, 0xf1, 0xf1, 0x73, 0x37, 0x1f},
	['decor-2'] = {0xf8, 0xec, 0xce, 0x8f, 0x8f, 0xce, 0xec, 0xf8},
	['decor-3'] = {0xff, 0xe7, 0xe7, 0x99, 0x99, 0xe7, 0xe7, 0xff},
	['decor-4'] = {0x7f, 0xa3, 0xdd, 0xbb, 0x77, 0xf0, 0xf7, 0xf8},
	['decor-5'] = {0xb6, 0x6b, 0xbd, 0x6a, 0xb7, 0x55, 0xbe, 0x55},
	['decor-6'] = {0x6d, 0xb6, 0x6b, 0xdd, 0xaa, 0x77, 0xb5, 0xda},
	['decor-7'] = {0xad, 0xd6, 0x6b, 0xb5, 0xda, 0x56, 0xad, 0xda},
	['decor-8'] = {0xe7, 0xdb, 0xbd, 0xa5, 0xbd, 0xdb, 0xb5, 0x6e},
	['decor-9'] = {0xe3, 0xdd, 0xb6, 0xa5, 0xbd, 0xdb, 0x52, 0xbd},
	['decor-10'] = {0x77, 0xad, 0xda, 0x77, 0xad, 0xda, 0x77, 0xad},
	['decor-11'] = {0x66, 0xdb, 0xbd, 0x66, 0x66, 0xbd, 0xdb, 0x66},
	['decor-12'] = {0xaa, 0xaa, 0xff, 0x20, 0xef, 0x28, 0xeb, 0x2a},
	['decor-13'] = {0xff, 0x81, 0xbd, 0xa5, 0xa5, 0xbd, 0x81, 0xff},
	['decor-14'] = {0xb6, 0x6d, 0xdb, 0xb6, 0x6d, 0xdb, 0xb6, 0x6d},
	['decor-15'] = {0x7f, 0x40, 0x5f, 0x51, 0x55, 0x5d, 0x41, 0x7f},
	['decor-16'] = {0x66, 0xbd, 0xc3, 0x7e, 0x7e, 0xc3, 0xbd, 0x66},
	['decor-17'] = {0xcf, 0x9f, 0x3f, 0x6e, 0xe7, 0xf1, 0xf8, 0xee},
	['decor-18'] = {0x1e, 0xee, 0xc2, 0xd9, 0x9b, 0x43, 0x77, 0x78},
	['decor-19'] = {0x9d, 0x66, 0xda, 0xbd, 0xbd, 0x5b, 0x66, 0xb9},
	['decor-20'] = {0xff, 0x55, 0xff, 0xdd, 0xff, 0x57, 0xff, 0xdd},
	['decor-21'] = {0x99, 0x7e, 0x66, 0xdb, 0xdb, 0x66, 0x7e, 0x99},
	['decor-22'] = {0x7e, 0xbd, 0xc3, 0xdb, 0xdb, 0xc3, 0xbd, 0x7e},
	['decor-23'] = {0x55, 0xba, 0x65, 0xca, 0x95, 0xaa, 0x55, 0xaa},
	['decor-24'] = {0xab, 0x77, 0xfa, 0x7d, 0xbe, 0x5f, 0xee, 0xd5},
	['decor-25'] = {0xeb, 0xf7, 0xeb, 0xdd, 0xbe, 0x7f, 0x7f, 0x9c},
	['decor-26'] = {0xEE, 0xD7, 0xBB, 0x6D, 0xB6, 0xDD, 0xEB, 0x77},

	-- Noise

	['noise-1'] = {0xfb, 0xdf, 0x7d, 0xef, 0xff, 0xbb, 0xef, 0xfe},
	['noise-2'] = {0xff, 0xf7, 0xbe, 0xff, 0xef, 0xff, 0xfd, 0xdf},
	['noise-3'] = {0xfb, 0x7f, 0xdd, 0xef, 0x7e, 0xf7, 0xbe, 0xf7},
	['noise-4'] = {0xbb, 0x7d, 0xef, 0xbe, 0xdf, 0xf7, 0xbe, 0xdb},
	['noise-5'] = {0xeb, 0xbe, 0xf7, 0xba, 0xdf, 0xb6, 0xfb, 0x6d},
	['noise-6'] = {0x66, 0x99, 0xa5, 0x5a, 0x5a, 0xa5, 0x99, 0x66},
	['noise-7'] = {0x5c, 0x5c, 0xea, 0xea, 0x47, 0x47, 0xaa, 0xaa},

	-- Emojis

	['emoji'] = {0x0, 0x3c, 0x7e, 0x5a, 0x7e, 0x66, 0x3c, 0x0},
	['emoji-smile'] = {0x0, 0x3c, 0x5a, 0x7e, 0x5a, 0x66, 0x3c, 0x0},
	['emoji-fun'] = {0x0, 0x3c, 0x5a, 0x7e, 0x42, 0x66, 0x3c, 0x0},
	['emoji-surprise'] = {0x0, 0x3c, 0x5a, 0x7e, 0x66, 0x66, 0x3c, 0x0},
	['emoji-sad'] = {0x0, 0x3c, 0x5a, 0x7e, 0x66, 0x5a, 0x3c, 0x0},
	['emoji-scream'] = {0x0, 0x3c, 0x5a, 0x7e, 0x42, 0x42, 0x3c, 0x0},
	['emoji-angry'] = {0x0, 0x3c, 0x5a, 0x7e, 0x42, 0x5a, 0x3c, 0x0},
	['emoji-pirate'] = {0x0, 0x34, 0x4E, 0x4A, 0x3E, 0x66, 0x3C, 0x0},
	['emoji-skull'] = {0x0, 0x3C, 0x7E, 0x5A, 0x7E, 0x24, 0x3C, 0x0},
	['emoji-alien'] = {0x0, 0x3C, 0x5A, 0x5A, 0x7E, 0x24, 0x18, 0x0},


	-- Misc

	['heart-1'] = {0xff, 0xc9, 0xb6, 0xbe, 0xdd, 0xeb, 0xf7, 0xff},
	['heart-2'] = {0xff, 0xc9, 0x80, 0x80, 0xc1, 0xe3, 0xf7, 0xff},
	['pacman-1'] = {0xff, 0xe3, 0xdd, 0xbb, 0xb7, 0xbb, 0xdd, 0xe3},
	['tree-1'] = {0xff, 0xf7, 0xeb, 0xf7, 0xc9, 0xf7, 0x88, 0xf7},
}


local gfxSetPattern <const> = playdate.graphics.setPattern

-- Caching of inverted patterns
local caching <const> = true


-- Set pattern
---@param val string, table - pattern
GFXP.set = function (val)

	local pattern

	if (type(val) == 'string') then

		pattern = GFXP.lib[val]

		if (not pattern) then
			
			-- Finding transformation flags
			if (string.find(val, '-?[irt]+$')) then
				
				pattern = GFXP._transformByFlag(val)
				
				-- Caching
				if (caching and pattern) then
					GFXP.lib[val] = pattern
				end
			end
			
		end

	elseif (type(val) == 'table' and (#val == 8 or #val == 16)) then
		pattern = val
	end

	-- Set pattern
	if (pattern) then
		gfxSetPattern(pattern)
	else
		print('GFXP: Unknown pattern. Value is "' .. val .. '" (' .. type(val) .. ')')
	end

end


-- Transform pattern by flag
---@param val string	- pattern name
---@return table 		- pattern
GFXP._transformByFlag = function (val)
	
	-- Pattern w/ id, 'name-1irt'
	local flags = string.match(val, '[0-9]([irt]+)$')
	local suffix = 1
	local pattern = nil
	local clone = nil
	
	if (not flags) then
		-- Pattern w/o id,'name-irt'
		flags = string.match(val, '[a-z]-([irt]+)$')
		suffix = 2
	end
	
	if (flags) then
		
		pattern = GFXP.lib[val:sub(1, -(#flags + suffix))]

		if (pattern) then
			clone = table.shallowcopy(pattern)
			
			for flag in string.gmatch(flags, '%w') do
				GFXP._transformations[flag](clone)
			end

			pattern = clone
		end
	end

	return pattern
end


-- Transforms
GFXP._transformations = {
	
	-- Invert 
	---@param pattern table
	i = function (pattern)
		for i = 1, 8 do
			pattern[i] = pattern[i] ~ 255
		end
	end,
	
	-- Random
	---@param pattern table
	r = function (pattern)
		for i = 1, 8 do
			pattern[i] = math.random(0, 255)
		end
	end,
	
	-- Transparency
	---@param pattern table
	t = function (pattern)
		for i = 1, 8 do
			table.insert(pattern, pattern[i] ~ 255)
		end
	end
}

