import UIKit

public extension CGFloat {
    /**
     Returns a random floating point number between 0.0 and 1.0, inclusive.
     */
    public static func random() -> CGFloat {
        return CGFloat(Float(arc4random()) / 0xFFFFFFFF)
    }
}

extension String {
    var uppercaseFirst: String {
        return String(characters.prefix(1)).uppercased() + String(characters.dropFirst())
    }
}

struct Extension {
    {{#iosExtensions}}
    struct {{&name}} {}
    {{/iosExtensions}}
}

class GameViewController: UIViewController {
    var client: Client! = Client()
    var renderer: Renderer! = Renderer()
    var customApp: CustomApp!
    var frameDelay: Double = 0
    var frameTime: Double = 0

    @objc private func animationFrame() {
        let time = CACurrentMediaTime()
        frameDelay = (time - frameTime) * 1000;
        frameTime = time
        client.sendData()
        client.js.callAnimationFrame()
    }

    private func initClient() {
        client.actions[InAction.setWindow] = {
            (reader: Reader) in
            self.view.addSubview(self.renderer.getItemFromReader(reader)!.view)
        }
    }

    private func initRenderer() {
        renderer.app = self
        (UIApplication.shared as! NeftApplication).renderer = renderer
    }

    override func viewDidLoad() {
        App.app = self

        initClient()
        initRenderer()

        // animation frame
        let updater = CADisplayLink(target: self, selector: #selector(GameViewController.animationFrame))
        updater.frameInterval = 1
        updater.add(to: RunLoop.current, forMode: RunLoopMode.commonModes)

        super.viewDidLoad()

        // init custom
        self.customApp = CustomApp()
        initExtensions()

        // run
        self.renderer.load()
        self.client.js.runScript("neft")

        // watch on js bundle file change
        {{#buildServerUrl}}
        watchOnBundleChange(url: "{{&buildServerUrl}}/newBundle/ios")
        {{/buildServerUrl}}
    }

    private func watchOnBundleChange(url: String) {
        var req = URLRequest(url: URL(string: url)!)
        let session = URLSession.shared
        req.timeoutInterval = 0

        let task = session.dataTask(with: req, completionHandler: {
            (data, response, error) in
            let js = data != nil ? NSString(data: data!, encoding: String.Encoding.utf8.rawValue)! : ""
            if (js != "") {
                DispatchQueue.main.async {
                    self.runJsBundle(code: js as String)
                    self.watchOnBundleChange(url: url)
                }
            } else {
                DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(Int(1000))) {
                    self.watchOnBundleChange(url: url)
                }
            }
        })

        task.resume()
    }

    private func initExtensions() {
        {{#iosExtensions}}
        Extension.{{&name}}.register()
        {{/iosExtensions}}
    }

    private func runJsBundle(code: String) {
        // clear
        client.destroy()
        view.subviews.forEach({ $0.removeFromSuperview() })

        // init classes
        client = Client()
        initClient()
        renderer = Renderer()
        initRenderer()
        initExtensions()

        // run
        renderer.load()
        client.js.runCode(code)
    }

    override var shouldAutorotate : Bool {
        return false
    }

    override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
        if UIDevice.current.userInterfaceIdiom == .phone {
            return .allButUpsideDown
        } else {
            return .all
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    override var prefersStatusBarHidden : Bool {
        return false
    }
}
