<?xml version="1.0" encoding="utf-8"?>
<!--
    Copyright © 2017-2021 Amebis

    This file is part of ZRCola.

    ZRCola is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    ZRCola is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with ZRCola. If not, see <http://www.gnu.org/licenses/>.
-->
<package>
	<job id="CanoPerm">
		<runtime>
			<description>Generates character index permutations - Amebis, Copyright © 2017</description>
			<unnamed name="&lt;Pattern&gt;" required="true" helpstring="Cannonical form (X=unmoveable character; 0-9=moveable character, characters of the same number must preserve global order of appearance; maximum 10 characters)"/>
			<example>
Example:
CanoPerm.wsf &quot;X01112&quot;
</example>
		</runtime>
		<script language="JScript"><![CDATA[
			if (WScript.Arguments.Unnamed.Length < 1) {
				WScript.Arguments.ShowUsage();
				WScript.Quit(1);
			}

			var
				pattern_src = WScript.Arguments.Unnamed(0),
				pattern = new Array();
			
			// Parse pattern.
			for (var i = 0, n = pattern_src.length; i < n; i++) {
				switch (pattern_src.charAt(i).toUpperCase()) {
				case 'X': pattern.push(new Character(-1, i)); break;
				case '0': pattern.push(new Character( 0, i)); break;
				case '1': pattern.push(new Character( 1, i)); break;
				case '2': pattern.push(new Character( 2, i)); break;
				case '3': pattern.push(new Character( 3, i)); break;
				case '4': pattern.push(new Character( 4, i)); break;
				case '5': pattern.push(new Character( 5, i)); break;
				case '6': pattern.push(new Character( 6, i)); break;
				case '7': pattern.push(new Character( 7, i)); break;
				case '8': pattern.push(new Character( 8, i)); break;
				case '9': pattern.push(new Character( 9, i)); break;
				default:
					throw new Error("Character '" + pattern_src.charAt(i) + "' is not a valid pattern character. Only 0-9 and X are allowed.");
				}
			}

			var output = "";
			Permutate(pattern, "");
			WScript.Echo(output);


			function Character(grp, idx)
			{
				this.group = grp;
				this.index = idx;
				return this;
			}


			function Permutate(pattern, prefix)
			{
				var n = pattern.length;
				if (n) {
					if (pattern[0].group < 0) {
						// Unmoveable character.
						var c = pattern.shift();
						Permutate(pattern, prefix + c.index);
					} else {
						var found = new Array();
						for (var i = 0; i < n; i++) {
							var c = pattern[i];
							if (c.group < 0) {
								// Unmoveable character.
								break;
							} else {
								if (!(c.group in found)) {
									var p = pattern.slice(0);
									p.splice(i, 1);
									Permutate(p, prefix + c.index);
									found[c.group] = true;
								}
							}
						}
					}
				} else {
					// This is the end.
					output += (output.length ? "," : "") + prefix;
				}
			}

			WScript.Quit(0);
		]]></script>
	</job>

</package>
