package neighborsPins

import (
    "math/rand"
    "strconv"
)

type PtrFunc func([131]byte) ([131]byte,bool,bool)
var GetCandidatePins map[string]PtrFunc
const NBPINS = 131

type MEMORY struct {
    numPin int
    numWheel int
    roues [6]int
    limit [6][2]int
    k1, k2 int
    kk1, kk2 int
    idx int
}

var T MEMORY 

func InitMEMORY() {
    T.numPin = 0
    T.numWheel = 0
    T.roues = [6]int{26,25,23,21,19,17}
    T.limit = [6][2]int{{0,25},{26,50},{51,73},{74,94},{95,113},{114,130}}
    T.k1 = 0
    T.k2 = 1
    T.kk1 = 26; 
    T.kk2 = 0
    T.idx = 0
}

func SameThing(current [131]byte) ([131]byte,bool,bool) {
    return current, true, false
}

func ToogleEachPin(current [131]byte) ([131]byte,bool,bool) {
    var finish bool
    var newPin byte
    var futur [131]byte 

    if  current[ T.numPin ] == '0' {
        newPin = '1'
    } else {
        newPin = '0'
    }
    futur = current
    futur[ T.numPin ] = newPin
    if T.numPin == NBPINS - 1 {
        finish = true; T.numPin = 0
    } else {
        finish = false; T.numPin ++
    }
    return futur, finish, false
}

func InverseAll(current [131]byte) ([131]byte,bool,bool) {
    var newPin byte
    var futur [131]byte

    for i:=0; i<NBPINS; i++ {
        if  current[i] == '0' {
            newPin = '1'
        } else {
            newPin = '0'
        }
        futur[i] = newPin
    }
    return futur,true,false
}
func InverseAWheel(current [131]byte) ([131]byte,bool,bool) {
    var finish bool
    var newPin byte
    var futur [131]byte

    debut := T.limit[ T.numWheel ][0]
    fin   := T.limit[ T.numWheel ][1]

    futur = current
    for i:=debut; i<=fin ; i++ {
        if  current[i] == '0' {
            newPin = '1'
        } else {
            newPin = '0'
        }
        futur[i] = newPin
    }
    T.numWheel ++
    if T.numWheel == len(T.roues) {
        T.numWheel = 0
        finish = true
    } else { 
        finish = false
    }
    return futur,finish, false
}

func SwapPinsInsideWheel(current [131]byte) ([131]byte,bool,bool) {
    var finish bool 
    var futur [131]byte 

    finish = false
    fin   := T.limit[ T.numWheel ][1]
    p1 := T.k1 ; p2 := T.k2 ; T.k2 ++
    if (T.k2 - 1)  == fin {
        T.k1 ++ ; T.k2 = T.k1 + 1
    }
    if (T.k1 == fin ) && (T.k2 == fin + 1) {
        T.numWheel ++
        if T.numWheel == len(T.roues) {
            T.numWheel = 0
            finish = true
            T.k1 = 0 ; T.k2 = 1
        } else {
            T.k1 = fin + 1 ; T.k2 = fin + 2
        }
    }
    if current[p1] == current[p2] {
        return current, finish, true
    }
    futur = current
    x := current[p1]
    futur[p1] = current[p2]
    futur[p2] = x
    return futur,finish, false
}

func SwapPinsOutsideWheel(current [131]byte) ([131]byte,bool,bool) {
    var finish bool
    var futur [131]byte 

    finish = false
    fin1  := T.limit[ T.numWheel + 1 ][1]
    fin2  := T.limit[ T.numWheel ][1]
    debut2:= T.limit[ T.numWheel ][0]

    p1 := T.kk1 ; p2 := T.kk2 
    if T.kk1 == (fin1 + 1) {
        T.numWheel ++
        if T.numWheel == len(T.roues) -1  {
            T.numWheel = 0
            finish = true
            T.kk1 = 26; T.kk2 = 0
            return current, finish, true
        } else {
            T.kk2 = fin2 + 1
        }
    } else {
        T.kk2 ++
        if T.kk2 == fin2 + 1 {
            T.kk1 ++; T.kk2 = debut2
        }
    }
    if current[p1] == current[p2] {
        return current, finish, true
    }
    futur = current
    x := current[p1]
    futur[p1] = current[p2]
    futur[p2] = x
    return futur,finish, false
}

func InitPins() string {
    currentKeyPins := ""

    var roues [6]int = [6]int{26,25,23,21,19,17}

    for i := 0; i < 6; i++ {
        for j := 0; j<roues[i]; j++ {
          currentKeyPins += strconv.Itoa(rand.Intn(2))
        }
        if i != 5 { currentKeyPins += "," }
    }
    return currentKeyPins
}   


func init() {
    InitMEMORY()

    GetCandidatePins = map[string]PtrFunc{ 
        "TE":   ToogleEachPin,
        "SI":   SwapPinsInsideWheel,
        "SO":   SwapPinsOutsideWheel,
        "IW":   InverseAWheel,
        "IA":   InverseAll,
        "ST":   SameThing,
    }
}
