#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Generating NoMachine NX scrambled key according to
https://www.nomachine.com/AR01C00125
"""

import sys
import random
from xml.sax.saxutils import escape


class NXKeyGen:
    """
    NXKeyGen class
    Creates NoMachine NX scrambled keys
    """
    numValidCharList = 85
    dummyString = "{{{{"

    def __init__(self, password):
        """
        Initialize the class

        Keyword arguments:
        @param password -- Password that will be scrambled
        """
        self.password = password

    def getEncrypted(self):
        """
        Encrypt (scramble) the given password

        Keyword arguments:
        @return scrambleString  --  Scrambled version of the original
                                    password
        """
        return self.scrambleString(self.password)

    def getvalidCharList(self, pos):
        """
        Valid character list

        Keyword arguments:
        @return validcharlist -- List of the valid characters
        """
        validcharlist = [
            "!",  "#", "$",  "%",  "&",  "(", ")",  "*",  "+",  "-",
            ".",  "0",   "1",  "2",   "3",  "4",  "5",  "6", "7", "8",
            "9", ":",  ";",  "<",  ">",  "?",  "@",  "A",  "B", "C",
            "D",  "E",  "F",  "G",  "H",  "I",  "J",  "K",  "L", "M",
            "N", "O",  "P",  "Q",  "R",  "S",  "T", "U", "V", "W",
            "X",  "Y",  "Z",  "[", "]",  "_",  "a",  "b",  "c",  "d",
            "e",  "f",  "g",  "h",  "i",  "j",  "k",  "l",  "m",  "n",
            "o",  "p",  "q",  "r",  "s",  "t",  "u",  "v",  "w",  "x",
            "y",  "z",  "{",  "|",  "}"]
        return validcharlist[pos]

    def encodePassword(self, p):
        """
        Password encoder

        Keyword arguments:
        @return sPass -- Encoded password
        """
        sPass = ":"
        sTmp = ""
        if not p:
            return ""
        for i in range(len(p)):
            c = p[i:i+1]
            a = ord(c)
            sTmp = str(a + i + 1) + ":"
            sPass += sTmp
            sTmp = ""
        return sPass

    def findCharInList(self, c):
        """
        Character position finder

        Keyword arguments:
        @param c    -- Character that needs to be matched if valid
        @return i   -- Place where the character is in the valid list
        """
        i = -1
        for j in range(self.numValidCharList):
            randchar = self.getvalidCharList(j)
            if randchar == c:
                i = j
                return i
        return i

    def getRandomValidCharFromList(self):
        """
        Random valid character getter

        Keyword arguments:
        @return char -- Valid character placed 0-60 in the valid list
        """
        return self.getvalidCharList(random.randint(0, 60))

    def scrambleString(self, s):
        """
        Password scrambler

        Keyword arguments:
        @param s     -- Password that needs to be scrambled
        @return sRet -- NoMachine NX scrambled password
        """
        sRet = ""
        if not s:
            return s
        strp = self.encodePassword(s)
        if len(strp) < 32:
            sRet += self.dummyString
        for iR in reversed(range(len(strp))):
            sRet += strp[iR:iR+1]
        if len(sRet) < 32:
            sRet += self.dummyString
        app = self.getRandomValidCharFromList()
        k = ord(app)
        l = k + len(sRet) - 2
        sRet = app + sRet
        for i1 in range(1, len(sRet)):
            app2 = sRet[i1: i1 + 1]
            j = self.findCharInList(app2)
            if j == -1:
                return sRet
            i = (j + l * (i1 + 1)) % self.numValidCharList
            car = self.getvalidCharList(i)
            sRet = self.substr_replace(sRet, car, i1, 1)
        c = (ord(self.getRandomValidCharFromList())) + 2
        c2 = chr(c)
        sRet = sRet + c2
        return escape(sRet)

    def substr_replace(self, in_str, ch, pos, qt):
        """
        Replace a character at a special position
        """
        clist = list(in_str)
        count = 0
        tmp_str = ''
        for key in clist:
            if count != pos:
                tmp_str += key
            else:
                tmp_str += ch
            count = count+1
        return tmp_str


if __name__ == "__main__":
    NXPass = NXKeyGen(sys.argv[1])
    print NXPass.password
    print NXPass.getEncrypted()
