     func decrypt(from text: String, key: String) -> String?
 }
 
+extension Cryptography {
+    fileprivate func asciiIndex(ofChar char: Character) -> UInt32 {
+        let unicodeScalars = String(char).unicodeScalars
+        
+        return unicodeScalars[unicodeScalars.startIndex].value
+    }
+    
+    fileprivate func encipherChar(char: Character, shiftBy shift: Int32, base: Character) -> Character {
+        let baseIndex = asciiIndex(ofChar: base)
+        let charIndex = asciiIndex(ofChar: char)
+        let resIndex = baseIndex + UInt32((Int32(charIndex) - Int32(baseIndex) + shift + 26) % 26)
+        
+        return Character(UnicodeScalar(resIndex)!)
+    }
+    
+    fileprivate func shiftOffset(ofChar char: Character) -> Int32 {
+        let start: Character
+        switch char {
+        case "a"..."z": start = "a"
+        case "A"..."Z": start = "A"
+        default: start = char
+        }
+        return Int32(asciiIndex(ofChar: char) - asciiIndex(ofChar: start))
+    }
+}
+
 
 // MARK: - CaesarCipher
 struct CaesarCipher: Cryptography {

        
        return encrypt(from: text, key: newKey)
    }
    
    private func asciiIndex(withChar char: Character) -> UInt32 {
        let unicodeScalars = String(char).unicodeScalars
        
        return unicodeScalars[unicodeScalars.startIndex].value
    }
    
    private func encipherChar(char: Character, shiftBy shift: Int32, base: Character) -> Character {
        let baseIndex = asciiIndex(withChar: base)
        let charIndex = asciiIndex(withChar: char)
        let resIndex = baseIndex + UInt32((Int32(charIndex) - Int32(baseIndex) + shift + 26) % 26)
        
        return Character(UnicodeScalar(resIndex)!)
    }
    
}

// MARK: - SubstitutionCipher

    }
}


// MARK: - vigenère
struct Vigenere: Cryptography {
    var name = "vigenère Cipher"
    var defaultKey = "SESAME"
    
    func cipherText(from text: String, key: String, encrypt: Bool) -> String? {
        var newCharacters = [Character]()
        
        text.characters.enumerated().forEach { (index, ch) in
            
            let keyChar = getKeyChar(fromKey: key, index: index)
        
            let shift: Int32
            if encrypt {
                shift = shiftOffset(ofChar: keyChar)
            } else {
                shift = -shiftOffset(ofChar: keyChar)
            }
            
            let cipherChar: Character
            switch ch {
            case "a"..."z": cipherChar = encipherChar(char: ch, shiftBy: shift, base: "a")
            case "A"..."Z": cipherChar = encipherChar(char: ch, shiftBy: shift, base: "A")
            default: cipherChar = ch
            }
            
            newCharacters.append(cipherChar)
        }
        
        return String(newCharacters)
    }
    
    private func getKeyChar(fromKey key: String, index: Int) -> Character {
        let offset = index % key.characters.count
        let index = key.index(key.startIndex, offsetBy: offset)
        let keyChar = key[index]
        
        return keyChar
    }
    
    func encrypt(from text: String, key: String) -> String? {
        return cipherText(from: text, key: key, encrypt: true)
    }
    
    func decrypt(from text: String, key: String) -> String? {
        return cipherText(from: text, key: key, encrypt: false)
    }
}

// MARK: - Enigma
struct Enigma: Cryptography {
    var name = "Enigma"
    var defaultKey = "default key"
    
    func encrypt(from text: String, key: String) -> String? {
        return nil
    }
    
    func decrypt(from text: String, key: String) -> String? {
        return nil
    }
    
}




