/*
 * Copyright (c) 2004-2014, Willem Cazander
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided
 * that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 *   following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
 *   the following disclaimer in the documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package	org.x4o.o2o;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.PrimitiveIterator;

///
/// CDC1604DashP6 has 27 pie slice number systems "Packed" for MATH and BASIC letters in a "Six" bit encoding.
/// 
/// This is used as the first 64 word numbers of the china four corner method, and acts like ascii glue for adult 18 bit computers.
///
/// ASCII 8 bit can only encoding 10 number glyphs, this 6 bit format can encode 378 different number glyphs.
/// (1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20+21+22+23+24+25+26+27)
///
/// With pie's the path to zero is: real ONE, relative ONE, real ONE.
///
/// @author Willem Cazander
/// @version 1.0 Dec 22, 2024
///
public enum CDC1604DashP6 {
	// [__NUL][__PIE][__GLUE][__ESC] [__LINE][__SPACE]?! {[(< }])>
	// ~+-* ,.:; '"`^ =#$%
	// |_\/ @ABC DEFG HIJK
	// LMNO PQRS TUVW XYZ&
	
	/// Indicator for termination of pussy strings, which is the compatibility duel octal, with the CDC 1604 computers.
	__NUL('\u0000'),
	/// Select packed pie number encoding.
	/// A = 1, first P6 is terminator select, than next P6 _A++ select pie part 1-27, until other P6 stops it.
	/// Example ascii "012" is
	/// 0 = __PIE NX01_A NX01_A (__PIE T001 PART_1)
	/// 12 = __PIE NX09_I NX01_A NX02_B (__PIE T009 PART_1+2)
	__PIE('\u0001'),
	/// Word glue to flag for automatic casing and/or separator in renderer.(by user-pref per context)
	/// The example "__SPACE __GLUE NX06_F NX15_O NX15_O __GLUE NX02_B NX01_A NX18_R"
	///  Can be rendered  as " FooᐧBar" or " fOObAR" or " FOO_BAR" etc/etc. 
	__GLUE('\u0002'),
	/// Escape to direct control code. (note only needed for 6 bit and 8 bit systems)
	__ESC('\u0003'),
	__LINE('\n'),
	__SPACE(' '),
	_QUESTION('?'),
	_EXCLAMATION('!'),
	
	TAG_CURLY_LEFT('{'),
	TAG_SQUARE_LEFT('['),
	TAG_ROUND_LEFT('('),
	TAG_COMPARE_LEFT('<'),
	TAG_CURLY_RIGHT('}'),
	TAG_SQUARE_RIGHT(']'),
	TAG_ROUND_RIGHT(')'),
	TAG_COMPARE_RIGHT('>'),
	
	_TILDE('~'),
	_PLUS('+'),
	_MINUS('-'),
	_ASTERISK('*'),
	_COMMA(','),
	_DOT('.'),
	_COLON(':'),
	_SEMICOLON(';'),
	_APOSTROPHE('\''),
	_QUOTATION('\"'),
	_BACKTICK('`'),
	_CARET('^'),
	_EQUALS('='),
	_HASH('#'),
	_DOLLAR('$'),
	_PERCENT('%'),
	
	BAR_VERTICAL('|'),
	BAR_UNDER('_'),
	BAR_V_LEFT('\\'),
	BAR_V_RIGHT('/'),
	_AT('@'),
	/// The tone letter 'A' is "one" and is equal to 'a', if your computer is expensive and has a lower-case char ROM, than this is 'a' except after __GLUE marker.
	NX01_A('A', "Æ æ Å å Ǻ ǻ Ḁ ḁ ẚ Ă ă Ặ ặ Ắ ắ Ằ ằ Ẳ ẳ Ẵ ẵ Ȃ ȃ Â â Ậ ậ Ấ ấ Ầ ầ Ẫ ẫ Ẩ ẩ Ả ả Ǎ ǎ Ⱥ ⱥ Ȧ ȧ Ǡ ǡ Ạ ạ Ä ä Ǟ ǟ À à Ȁ ȁ Á á Ā ā Ā̀ ā̀ Ã ã Ą ą Ą́ ą́ Ą̃ ą̃ A̲ a̲ ᶏ"),
	NX02_B('B', "Ƀ ƀ Ḃ ḃ Ḅ ḅ Ḇ ḇ Ɓ ɓ ᵬ ᶀ"),
	NX03_C('C', "Ć ć Ĉ ĉ Č č Ċ ċ Ḉ ḉ Ƈ ƈ C̈ c̈ Ȼ ȼ Ç ç Ꞔ ꞔ Ꞓ ꞓ"),
	NX04_D('D', "Đ đ Ꟈ ꟈ Ɗ ɗ Ḋ ḋ Ḍ ḍ Ḑ ḑ Ḓ ḓ Ď ď Ḏ ḏ"),
	NX05_E('E', "Ĕ ĕ Ḝ ḝ Ȇ ȇ Ê ê Ê̄ ê̄ Ê̌ ê̌ Ề ề Ế ế Ể ể Ễ ễ Ệ ệ Ẻ ẻ Ḙ ḙ Ě ě Ɇ ɇ Ė ė Ė́ ė́ Ė̃ ė̃ Ẹ ẹ Ë ë È è È̩ è̩ Ȅ ȅ É é É̩ Ē ē Ḕ ḕ Ḗ ḗ Ẽ ẽ Ḛ ḛ Ę ę Ę́ ę́ Ę̃ ę̃ Ȩ ȩ E̩ e̩ ᶒ"),
	NX06_F('F', "Ƒ ƒ Ḟ ḟ ᵮ ᶂ Ꞙ ꞙ"),
	NX07_G('G', "Ǵ ǵ Ǥ ǥ Ĝ ĝ Ǧ ǧ Ğ ğ Ģ ģ Ɠ ɠ Ġ ġ Ḡ ḡ Ꞡ ꞡ ᶃ"),
	NX08_H('H', "Ĥ ĥ Ȟ ȟ Ħ ħ Ḩ ḩ Ⱨ ⱨ ẖ ẖ Ḥ ḥ Ḣ ḣ Ḧ ḧ Ḫ ḫ ꞕ Ꜧ ꜧ"),
	NX09_I('I', "Ị ị Ĭ ĭ Î î Ǐ ǐ Ɨ ɨ Ï ï Ḯ ḯ Í í Ì ì Ȉ ȉ Į į Į́ Į̃ Ī ī Ī̀ ī̀ ᶖ Ỉ ỉ Ȋ ȋ Ĩ ĩ Ḭ ḭ ᶤ"),
	NX10_J('J', "J́ j́ Ĵ ĵ J̌ ǰ Ɉ ɉ J̃ j̇̃"),
	NX11_K('K', "Ƙ ƙ Ꝁ ꝁ Ḱ ḱ Ǩ ǩ Ḳ ḳ Ķ ķ ᶄ Ⱪ ⱪ Ḵ ḵ"),
	NX12_L('L', "Ĺ ĺ Ł ł Ľ ľ Ḹ ḹ L̃ l̃ Ļ ļ Ŀ ŀ Ḷ ḷ Ḻ ḻ Ḽ ḽ Ƚ ƚ Ⱡ ⱡ"),
	NX13_M('M', "Ḿ ḿ Ṁ ṁ Ṃ ṃ M̃ m̃ ᵯ"),
	NX14_N('N', "Ń ń Ñ ñ Ň ň Ǹ ǹ Ṅ ṅ Ṇ ṇ Ņ ņ Ṉ ṉ Ṋ ṋ Ꞥ ꞥ ᵰ ᶇ"),
	NX15_O('O', "Ø ø Ǿ ǿ Ö ö Ȫ ȫ Ó ó Ò ò Ô ô Ố ố Ồ ồ Ổ ổ Ỗ ỗ Ộ ộ Ǒ ǒ Ő ő Ŏ ŏ Ȏ ȏ Ȯ ȯ Ȱ ȱ Ọ ọ Ɵ ɵ ᶱ Ơ ơ Ớ ớ Ờ ờ Ỡ ỡ Ợ ợ Ở ở Ỏ ỏ Ō ō Ṓ ṓ Ṑ ṑ Õ õ Ȭ ȭ Ṍ ṍ Ṏ ṏ Ǫ ǫ Ȍ ȍ O̩ o̩ Ó̩ ó̩ Ò̩ ò̩ Ǭ ǭ O͍ o͍"),
	NX16_P('P', "Ṕ ṕ Ṗ ṗ Ᵽ ᵽ Ƥ ƥ ᵱ ᶈ"),
	NX17_Q('Q', "ʠ Ɋ ɋ q̃"),
	NX18_R('R', "Ŕ ŕ Ɍ ɍ Ř ř Ŗ ŗ Ṙ ṙ Ȑ ȑ Ȓ ȓ Ṛ ṛ Ṝ ṝ Ṟ ṟ Ꞧ ꞧ Ɽ ɽ R̃ r̃ ᵲ ꭨ ᵳ ᶉ"),
	NX19_S('S', "Ś ś Ṡ ṡ ẛ Ṩ ṩ Ṥ ṥ Ṣ ṣ S̩ s̩ Ꞩ ꞩ Ꟊ ꟊ Ꟍ ꟍ Ŝ ŝ Ṧ ṧ Š š Ş ş Ș ș S̈ s̈ ᶊ Ȿ ȿ ᵴ ᶳ"),
	NX20_T('T', "Ť ť Ṫ ṫ ẗ Ţ ţ Ṭ ṭ Ʈ ʈ Ț ț ƫ Ṱ ṱ Ṯ ṯ Ŧ ŧ Ⱦ ⱦ Ƭ ƭ ᵵ ᶵ"),
	NX21_U('U', "Ŭ ŭ Ʉ ʉ ᵾ ᶶ Ꞹ ꞹ Ụ ụ Ü ü Ǜ ǜ Ǘ ǘ Ǚ ǚ Ǖ ǖ Ṳ ṳ Ú ú Ù ù Û û Ṷ ṷ Ǔ ǔ Ȗ ȗ Ű ű Ŭ ŭ Ư ư Ứ ứ Ừ ừ Ử ử Ự ự Ữ Ữ Ủ ủ Ū ū Ū̀ ū̀ Ū́ ū́ Ṻ ṻ Ū̃ ū̃ Ũ ũ Ṹ ṹ Ṵ ṵ ᶙ Ų ų Ų́ ų́ Ų̃ ų̃ Ȕ ȕ Ů ů"),
	NX22_V('V', "Ṽ ṽ Ṿ ṿ Ʋ ʋ ᶌ"),
	NX23_W('W', "Ẃ ẃ Ẁ ẁ Ŵ ŵ Ẅ ẅ Ẇ ẇ Ẉ ẉ ẘ"),
	NX24_X('X', "Ẍ ẍ Ẋ ẋ X̂ x̂ ᶍ"),
	NX25_Y('Y', "Ý ý Ỳ ỳ Ŷ ŷ Ÿ ÿ Ỹ ỹ Ẏ ẏ Ỵ ỵ ẙ Ỷ ỷ Ȳ ȳ Ɏ ɏ Ƴ ƴ"),
	NX26_Z('Z', "Ź ź Ẑ ẑ Ž ž Ż ż Ẓ ẓ Ẕ ẕ Ƶ ƶ ᵶ Ᶎ ᶎ Ⱬ ⱬ"),
	/// The 27th letter is at the end of the old english alphabet.
	NX27_AMPERSAND('&'),
	;
	
	private final byte codePoint;
	private final byte codePointLower;
	private final String aliases;
	
	private CDC1604DashP6(char codePoint) {
		this(codePoint, null);
	}
	
	private CDC1604DashP6(char codePoint, String aliases) {
		this.codePoint = (byte) codePoint;
		this.codePointLower = (byte) Character.toLowerCase(codePoint);
		this.aliases = aliases;
	}
	
	public byte cdcByte() {
		return (byte) ordinal();
	}
	
	public byte asciiByte() {
		return codePoint;
	}
	
	static public List<CDC1604DashP6> convertFromUnicode(String text) {
		return convertFromUnicode(text, false);
	}
	
	static public List<CDC1604DashP6> convertFromUnicode(String text, boolean strict) {
		String textSingleNewLines = text.replaceAll("\r\n", "\n");
		PrimitiveIterator.OfInt i = textSingleNewLines.codePoints().iterator();
		List<CDC1604DashP6> result = new ArrayList<>(text.length());
		CDC1604DashP6[] cdcChars = values();
		CDC1604DashP6 cdcNumberTerminator = null;
		while (i.hasNext()) {
			int codePoint = i.next();
			boolean found = false;
			if ('\r' == codePoint) {
				result.add(CDC1604DashP6.__LINE);
				continue;
			}
			for (CDC1604DashP6 v : cdcChars) {
				if (v.codePoint == codePoint) {
					result.add(v);
					found = true;
					cdcNumberTerminator = null;
					break;
				}
				if ('0' == codePoint) {
					if (!CDC1604DashP6.NX01_A.equals(cdcNumberTerminator)) {
						result.add(CDC1604DashP6.__PIE);
						result.add(CDC1604DashP6.NX01_A);
						cdcNumberTerminator = CDC1604DashP6.NX01_A;
					}
					result.add(CDC1604DashP6.NX01_A);
					found = true;
					break;
				}
				if (codePoint >= '1' && codePoint <= '9') {
					if (!CDC1604DashP6.NX09_I.equals(cdcNumberTerminator)) {
						result.add(CDC1604DashP6.__PIE);
						result.add(CDC1604DashP6.NX09_I);
						cdcNumberTerminator = CDC1604DashP6.NX09_I;
					}
					int cdcNumberOff = codePoint - '1'; // 0 = 1
					int cdcNumber = CDC1604DashP6.NX01_A.ordinal() + cdcNumberOff;
					result.add(CDC1604DashP6.values()[cdcNumber]);
					found = true;
					break;
				}
			}
			if (!found && !strict) {
				String codePointStr = Character.toString(codePoint);
				for (CDC1604DashP6 v : cdcChars) {
					if (v.codePointLower == codePoint) {
						result.add(v);
						found = true;
						cdcNumberTerminator = null;
						break;
					}
					if (v.aliases == null) {
						continue;
					}
					if (v.aliases.contains(codePointStr)) {
						result.add(v);
						found = true;
						cdcNumberTerminator = null;
						break;
					}
				}
			}
			if (!found) {
				throw new IllegalArgumentException("Unsupported char: '" + ((char)codePoint) + "' 0x" + Integer.toHexString(codePoint));
			}
		}
		return result;
	}
	
	static public String convertToUnicode(List<CDC1604DashP6> cdcChars) {
		StringBuilder buf = new StringBuilder();
		Iterator<CDC1604DashP6> cdc = cdcChars.iterator();
		CDC1604DashP6 numberMode = null;
		while (cdc.hasNext()) {
			CDC1604DashP6 cdcPoint = cdc.next();
			if (numberMode != null && (cdcPoint.ordinal() > numberMode.ordinal())) {
				numberMode = null; // out of range
			}
			if (numberMode != null && (cdcPoint.ordinal() < CDC1604DashP6.NX01_A.ordinal())) {
				numberMode = null; // below index 1 is end number mode
			}
			if (CDC1604DashP6.__GLUE.equals(cdcPoint)) {
				continue;
			}
			if (CDC1604DashP6.__PIE.equals(cdcPoint)) {
				if (!cdc.hasNext()) {
					break;
				}
				numberMode = cdc.next();
				continue;
			}
			if (numberMode == null) {
				buf.appendCodePoint(cdcPoint.asciiByte());
			} else {
				int terminatorNum = numberMode.ordinal() - CDC1604DashP6.NX01_A.ordinal() + 1;
				int valueNumber = cdcPoint.ordinal() - CDC1604DashP6.NX01_A.ordinal();
				appendTerminatorNumber(buf, terminatorNum, valueNumber);
			}
		}
		return buf.toString();
	}
	
	static private void appendTerminatorNumber(StringBuilder buf, int terminator, int value) {
		switch (terminator) {
		case 1:
			buf.appendCodePoint('0'); // T001 is zero for all 27 gematria number systems.
			return;
		case 2:
			if (value == 0) {
				buf.append("true"); // FIXME: T002ᖟGunPunchedHoles would be better, as it supports two-way conversion
			} else {
				buf.append("false");
			}
			return;
		//case 3:
		//	return; // TODO: after nether DB, generate add all terminator up to 27 from "number system" gun bullets.
		case 9:
			buf.appendCodePoint(('1' + value)); // 0 = 1
			return; // NOTE: Latin decimals are not decimals as zero is not a part of the pie.
		default:
			throw new IllegalArgumentException("Unsupported terminator index: " + terminator);
		}
	}
}