# m209 : The base Class of M209 

import string
import sys
import random
import math
from   bib_util import *

class Wheel:
    def __init__(self,alphabet,shift):
        self.alphabet = alphabet
        self.lg = len(alphabet)
        self.pins = []
        for i in range(self.lg):
            self.pins.append( 0 )
        self.position = 0
        self.shiftWindow = shift

    def setPinsON(self,car):
        i = string.index(self.alphabet,car)
        self.pins[i] = 1

    def setPinsOFF(self,car):
        i = string.index(self.alphabet,car)
        self.pins[i] = 0
        
    def getAPins(self,car):
        i = string.index(self.alphabet,car)
        return self.pins[i]

    def getShift(self):
        return self.shiftWindow

    def turnClockwise(self):
        self.position = (self.position + 1 ) % self.lg

    def turnCounterClockwise(self):
        self.position = (self.position + self.lg - 1 ) % self.lg 

    def getLg( self):
        return len( self.alphabet )

    def getPosition(self):
        return self.position

    def setPosition(self, newPosition ):
        self.position = newPosition

    def getExternalKey(self):
        return self.alphabet[ self.position ]

    def getExternalShiftedKey(self):
        return self.alphabet[(self.position + self.shiftWindow)%self.lg]

    def getInternalKey(self):
        ch = ""
        for i in range(self.lg):
            if self.pins[i] :
                ch = ch + self.alphabet[i]
            else:
                ch = ch + "_"
        return ch

    def isActive(self):
        pos_active = ( self.position + self.shiftWindow ) % self.lg
        if self.pins[ pos_active ] != 0:
            return 1
        else:
            return 0

    def zero(self):
        for i in range(self.lg):
            self.pins[i] = 0

    def info(self):
        print "Lenght       : ", self.lg
        print "Alphabet     : ", self.alphabet
        print "Shitf        : ", self.shiftWindow
        print "Pins         : ", self.pins
        print "Internal Key : ", self.getInternalKey()
        print "External key : ", self.getExternalKey()
        print "Position: ", self.position, " Actif : ", self.isActive()

class Hagelin:
    def __init__(self, lettre_decalage, debug):
        self.debug = debug
        self.decalage = string.index(string.ascii_uppercase,lettre_decalage)
        self.wheels = []
        self.wheels.append( Wheel("ABCDEFGHIJKLMNOPQRSTUVWXYZ",15 ) )
        self.wheels.append( Wheel("ABCDEFGHIJKLMNOPQRSTUVXYZ",14) )
        self.wheels.append( Wheel("ABCDEFGHIJKLMNOPQRSTUVX",13) )
        self.wheels.append( Wheel("ABCDEFGHIJKLMNOPQRSTU",12) )
        self.wheels.append( Wheel("ABCDEFGHIJKLMNOPQRS",11) )
        self.wheels.append( Wheel("ABCDEFGHIJKLMNOPQ",10  ) )
        self.nbOfWheels = len( self.wheels )
        self.lugs = [0]*6
        self.over = [0]*15
        self.counter  = 0

    def setSlide(self, lettre_decalage ):
        self.decalage = string.index(string.ascii_uppercase,lettre_decalage)

    def setDebug(self,debug):
        self.debug = debug

    def getDebug(self):
        return self.debug

    def setZeroOver(self):
        for i in range(len(self.over)):
            self.over[i]=0

    def setOverByKey(self,clef, valeur):
        overlaps = { '1-2':0, '1-3':1, '1-4':2, '1-5':3, '1-6':4, '2-3':5,
                     '2-4':6, '2-5':7, '2-6':8, '3-4':9, '3-5':10,'3-6':11,
                     '4-5':12,'4-6':13,'5-6':14 }
        indx = overlaps[clef] 
        self.over[indx] = valeur

    def setExternalKey( self, key ):
        for i in range( len(key) ):
            non_trouve = 1
            lettre_cle = key[i]
            lg = self.wheels[i].getLg()
            for j in range (lg):
                if lettre_cle == self.wheels[i].getExternalKey():
                    non_trouve = 0                  
                    break
                self.stepAWheel(i)
            if non_trouve: 
                print "**** Error: invalid external key  **** "; exit

    def setOver(self,lesOvers):
        self.over = lesOvers

    def getOver(self):
        return self.over

    def setLugs(self,lesLugs):
        self.lugs = lesLugs

    def getLugs(self):
        return self.lugs

    def setPinsON(self,laroue,char):
        self.wheels[laroue].setPinsON(char)

    def setPinsOFF(self,laroue,char):
        self.wheels[laroue].setPinsOFF(char)

    def setAllPins(self,laroue,ch):
        for i in range(len(ch)):
            if ch[i] == "1":
                self.setPinsON(laroue,
                self.wheels[laroue].alphabet[i] )
            else:
                self.setPinsOFF(laroue,
                self.wheels[laroue].alphabet[i] )

    def setAllPinsAllW(self,ch):
        self.setAllPins(0, ch[:26] )
        self.setAllPins(1, ch[26:51] )
        self.setAllPins(2, ch[51:74] )
        self.setAllPins(3, ch[74:95] )
        self.setAllPins(4, ch[95:114] )
        self.setAllPins(5, ch[114:] )

    def getPins(self,laroue,char):
        return self.wheels[laroue].getAPins(char)

    def stepAWheel(self, aWheel ):
        self.wheels[ aWheel ].turnClockwise()

    def step(self):
        for i in range( self.nbOfWheels ):      
            self.wheels[i].turnClockwise()
        self.counter = self.counter + 1

    def getPosition( self ):
        return self.counter

    def getPinsOfAWheel( self, aWheel ):
        return self.wheels[ aWheel ].getInternalKey()

    def stepBack(self):
        for i in range( self.nbOfWheels ):      
            self.wheels[i].turnCounterClockwise()
        self.counter = self.counter - 1
        if ( self.counter < 0 ):
            self.counter = 999

    def rewind(self):
        while ( self.counter != 0 ):
            self.stepBack()

    def getExternalKey( self ):
        ch = ""
        for i in range( self.nbOfWheels ):
            ch = ch + self.wheels[i].getExternalKey()
        return ch

    def cipher(self,char):
        shift = 0
        index = string.index(string.ascii_uppercase,char)
        activesPins = []
        for j in range( self.nbOfWheels ):
            if self.wheels[ j ].isActive():
                activesPins.append( 1 )
            else:
                activesPins.append( 0 )
        for j in range( self.nbOfWheels ):
            shift = shift + activesPins[j] * self.lugs[j]
        o = self.over
        shift = shift - o[0] * activesPins[0] * activesPins[1]
        shift = shift - o[1] * activesPins[0] * activesPins[2]
        shift = shift - o[2] * activesPins[0] * activesPins[3]
        shift = shift - o[3] * activesPins[0] * activesPins[4]
        shift = shift - o[4] * activesPins[0] * activesPins[5]
        shift = shift - o[5] * activesPins[1] * activesPins[2]
        shift = shift - o[6] * activesPins[1] * activesPins[3]
        shift = shift - o[7] * activesPins[1] * activesPins[4]
        shift = shift - o[8] * activesPins[1] * activesPins[5]
        shift = shift - o[9] * activesPins[2] * activesPins[3]
        shift = shift - o[10] * activesPins[2] * activesPins[4]
        shift = shift - o[11] * activesPins[2] * activesPins[5] 
        shift = shift - o[12] * activesPins[3] * activesPins[4]
        shift = shift - o[13] * activesPins[3] * activesPins[5]
        shift = shift - o[14] * activesPins[4] * activesPins[5]
        j = ( 26 + self.decalage - index + shift ) % 26 
        char2 = string.ascii_uppercase[ j ]
        if ( self.debug ):
            print "Counter: %03d Key: " % (self.getPosition()), 
            print "External Key: %6s " % (self.getExternalKey()),
            for i in range( self.nbOfWheels ):
                print "%d" % (activesPins[i]),
            print "%2d %c %c" % (shift, char, char2)
        self.step()
        return char2

    def getNbOfWheels(self):
        return self.nbOfWheels

    def toggleDebug( self ):
        if self.debug: self.debug = 0
        else: self.debug = 1

    def info(self):
        print "Slide   : ", self.decalage
        print "Lugs    : ", self.lugs
        print "Overlaps: ", self.over
        print "Actives Pins : ", 
        for i in range( self.nbOfWheels ):
            self.wheels[i].info()
#================================================
def chiffre( e, msg ):
        crypto = ""
        cpt = 0
        for i in range(len(msg)):
                car = e.cipher( msg[i] )
                crypto = crypto + car
                cpt = cpt + 1
        return crypto
#================================================
def restore( c, nomFichier ):
    if nomFichier == "":
        nomFichier = "config"
    f = open( nomFichier, "r" )
    for i in range(6):
        ch = f.readline()
        ch = ch.rstrip()
        lg = len(ch)
        for j in range(lg):
            if ch[j] != '_':
                c.setPinsON(i, ch[j] )
    ch = f.readline()
    ch = ch[0]
    #c.setLetterShift( ch )
    c.setSlide( ch )

    ch = f.readline()
    ch = ch.rstrip()
    lesLugs = ch.split(":")
    lesLugs = map(int,lesLugs)
    c.setLugs( lesLugs )

    ch = f.readline()
    nblignes = int (ch )
    for i in range( nblignes ):
        ch = f.readline()
        ch = ch.rstrip()
        (over_clef, over_nb) = ch.split(":")
        over_nb = int(over_nb)
        c.setOverByKey(over_clef, over_nb)
    f.close()
# ==== on fait juste un teste de chiffrement
if __name__ == "__main__":
    e = Hagelin ('Z',0)
#          01234567890123456789012345
    Pins="11010001101011000011011000"+\
         "0001101001110010011010100"+\
         "11000011010111000111111"+\
         "001011011000110100111"+\
         "0101110110001101001"+\
         "11010001001001101"
    e.setAllPinsAllW(Pins)
    Lugs="1:2:3:4:8:11"
    e.setLugs(map(int,Lugs.split(":")))
# overlaps: #4-5:1 #5-6:1
    Overs="0:0:0:0:0:0:0:0:0:0:0:0:1:0:1"
    e.setOver(map(int,Overs.split(":")))
    print chiffre(e,"AAAAAAAAAAAAAAAAAAAAAAAAAA")


