// The MIT License
//
// Copyright (c) 2015 Gwendal Roué
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

extension StandardLibrary {

    /**
    StandardLibrary.Logger is a tool intended for debugging templates.

    It logs the rendering of variable and section tags such as `{{name}}` and
    `{{#name}}...{{/name}}`.

    To activate logging, add a Logger to the base context of a template:

        let template = try! Template(string: "{{name}} died at {{age}}.")

        // Logs all tag renderings with NSLog():
        let logger = StandardLibrary.Logger()
        template.extendBaseContext(Box(logger))

        // Render
        let data = ["name": "Freddy Mercury", "age": 45]
        let rendering = try! template.render(Box(data))

        // In NSLog:
        // {{name}} at line 1 did render "Freddy Mercury" as "Freddy Mercury"
        // {{age}} at line 1 did render 45 as "45"
    */
    public final class Logger : MustacheBoxable {

        /**
        Returns a Logger.

        - parameter log: A closure that takes a String. Default one logs that
                         string with NSLog().
        - returns: a Logger
        */
        public init(log: ((String) -> Void)? = nil) {
            if let log = log {
                self.log = log
            } else {
                self.log = { print($0) }
            }
        }

        /**
        Logger adopts the `MustacheBoxable` protocol so that it can feed
        Mustache templates.

        You should not directly call the `mustacheBox` property. Always use the
        `Box()` function instead:

            localizer.mustacheBox   // Valid, but discouraged
            Box(localizer)          // Preferred
        */
        public var mustacheBox: MustacheBox {
            return MustacheBox(
                willRender: { (tag, box) in
                    if tag.type == .Section {
                        self.log("\(self.indentationPrefix)\(tag) will render \(box.valueDescription)")
                        self.indentationLevel += 1
                    }
                    return box
                },
                didRender: { (tag, box, string) in
                    if tag.type == .Section {
                        self.indentationLevel -= 1
                    }
                    if let string = string {
                        self.log("\(self.indentationPrefix)\(tag) did render \(box.valueDescription) as \(string.debugDescription)")
                    }
                }
            )
        }

        var indentationPrefix: String {
            return String(repeating: " " as Character, count: indentationLevel * 2)
        }

        private let log: (String) -> Void
        private var indentationLevel: Int = 0
    }
}
