<commit_before>//
//  main.swift
//  Hexaville
//
//  Created by <NAME> on 2017/05/17.
//
//

//
//  main.swift
//  Hexaville
//
//  Created by <NAME> on 2017/05/16.
//
//

#if os(Linux)
    import Glibc
#else
    import Darwin.C
#endif

import Foundation
import AWSSDKSwift
import Prorsum
import Core
import SwiftyJSON
import SwiftCLI
import Yaml
import HexavilleCore

let projectRoot = #file.characters
    .split(separator: "/", omittingEmptySubsequences: false)
    .dropLast(3)
    .map { String($0) }
    .joined(separator: "/")

enum HexavilleError: Error {
    case projectAlreadyCreated(String)
    case couldNotFindManifestFile(String)
    case pathIsNotForHexavillefile(String)
}

class GenerateProject: Command {
    let name = "generate"
    let shortDescription  = "Generate initial project"
    let projectName = Parameter()
    let dest = Key<String>("-o", "--dest", usage: "Destination for the project")
    
    func execute() throws {
        do {
            let out = (dest.value ?? FileManager.default.currentDirectoryPath) + "/\(projectName.value)"
            let packageSwiftPath = out+"/Package.swift"
            let ymlPath = out+"/Hexavillefile.yml"
            
            if FileManager.default.fileExists(atPath: packageSwiftPath) {
                throw HexavilleError.projectAlreadyCreated(out)
            }
            let hashids = Hashids(salt: UUID().uuidString)
            
            #if os(Linux)
                srandom(UInt32(time(nil)))
                let randomNumber = Int(UInt32(random() % 10000))
            #else
                let randomNumber = Int(arc4random_uniform(9999))
            #endif
            
            try FileManager.default.copyFiles(from: "\(projectRoot)/templates/SwiftProject", to: out)
            let hashId = hashids.encode(randomNumber)!
            let bucketName = "hexaville-\(projectName.value.lowercased())-\(hashId)-bucket"
            
            try String(contentsOfFile: ymlPath)
                .replacingOccurrences(of: "{{appName}}", with: projectName.value)
                .replacingOccurrences(of: "{{bucketName}}", with: bucketName)
                .write(toFile: ymlPath, atomically: true, encoding: .utf8)
            
            try String(contentsOfFile: packageSwiftPath)
                .replacingOccurrences(of: "{{appName}}", with: projectName.value)
                .write(toFile: packageSwiftPath, atomically: true, encoding: .utf8)
            
        } catch {
            print(error)
            throw error
        }
    }
}

func loadHexavilleFile(hexavilleFilePath: String) throws -> Yaml {
    let ymlString = try String(contentsOfFile: hexavilleFilePath)
    return try Yaml.load(ymlString)
}

class RoutesCommand: Command {
    let name = "routes"
    let shortDescription  = "Show routes and endpoint for the API"
    let stage = Key<String>("--stage", usage: "Deployment Stage. default is staging")
    
    func execute() throws {
        do {
            let cwd = FileManager.default.currentDirectoryPath<commit_msg>sanitize project name to pass bucket name validation<commit_after>//
//  main.swift
//  Hexaville
//
//  Created by <NAME> on 2017/05/17.
//
//

//
//  main.swift
//  Hexaville
//
//  Created by <NAME> on 2017/05/16.
//
//

#if os(Linux)
    import Glibc
#else
    import Darwin.C
#endif

import Foundation
import AWSSDKSwift
import Prorsum
import Core
import SwiftyJSON
import SwiftCLI
import Yaml
import HexavilleCore

let projectRoot = #file.characters
    .split(separator: "/", omittingEmptySubsequences: false)
    .dropLast(3)
    .map { String($0) }
    .joined(separator: "/")

enum HexavilleError: Error {
    case projectAlreadyCreated(String)
    case couldNotFindManifestFile(String)
    case pathIsNotForHexavillefile(String)
}

class GenerateProject: Command {
    let name = "generate"
    let shortDescription  = "Generate initial project"
    let projectName = Parameter()
    let dest = Key<String>("-o", "--dest", usage: "Destination for the project")
    
    func execute() throws {
        do {
            let out = (dest.value ?? FileManager.default.currentDirectoryPath) + "/\(projectName.value)"
            let packageSwiftPath = out+"/Package.swift"
            let ymlPath = out+"/Hexavillefile.yml"
            
            if FileManager.default.fileExists(atPath: packageSwiftPath) {
                throw HexavilleError.projectAlreadyCreated(out)
            }
            let hashids = Hashids(salt: UUID().uuidString)
            
            #if os(Linux)
                srandom(UInt32(time(nil)))
                let randomNumber = Int(UInt32(random() % 10000))
            #else
                let randomNumber = Int(arc4random_uniform(9999))
            #endif
            
            try FileManager.default.copyFiles(from: "\(projectRoot)/templates/SwiftProject", to: out)
            let hashId = hashids.encode(randomNumber)!
            
            func createBucketName(from projectName: String, hashId: String) -> String {
                let prefix = "hexaville-"
                let suffix = "-\(hashId)-bucket"

                let bucketNameMaxLength = 63
                let maxLength = bucketNameMaxLength - (prefix + suffix).characters.count

                let allowedCharacters = Set("abcdefghijklmnopqrstuvwxyz1234567890-".characters)
                let sanitizedCharacters = projectName
                    .lowercased()
                    .characters
                    .filter { allowedCharacters.contains($0) }
                    .prefix(maxLength)
                
                let sanitizedName = String(sanitizedCharacters)
                
                return prefix + sanitizedName + suffix
            }
            
            let bucketName = createBucketName(from: projectName.value, hashId: hashId)
                
            try String(contentsOfFile: ymlPath)
                .replacingOccurrences(of: "{{appName}}", with: projectName.value)
                .replacingOccurrences(of: "{{bucketName}}", with: bucketName)
                .write(toFile: ymlPath, atomically: true, encoding: .utf8)
            
            try String(contentsOfFile: packageSwiftPath)
                .replacingOccurrences(of: "{{appName}}", with: projectName.value)
                .write(toFile: packageSwiftPath, atomically: true, encoding: .utf8)
            
        } catch {
            print(error)
            throw error
        }
    }
}

func loadHexavilleFile(hexavilleFilePath: String) throws -> Yaml {
    let ymlString = try String(contentsOfFile: hexavilleFilePath)
    return try Yaml.load(ymlString)
}

class RoutesCommand: Command {
    let name = "routes"
    let shortDescription  = "Show routes and endpoint for the API"
    let stage = Key<String>("--stage", usage: "Deployment Stage. default is staging")
    
    func execute() throws {
        do {
            let cwd = FileManager.default.currentDirectoryPath
{'fraction_non_alphanumeric': 0.10281852171412137, 'fraction_numerical': 0.011647972389991372, 'mean_word_length': 2.145635459068295, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4199481', 'n_tokens_mistral': 2091, 'n_tokens_neox': 1940, 'n_words': 460}