//
//  Log.swift
//  eGauge
//
//  Created by egauge on 10/28/19.
//  Copyright © 2019 egauge. All rights reserved.
//

//  Internal log buffer
//

import Foundation

struct Log {

// Bitmaps that select debugging optinons
//
static let DBG_NONE  =     0x000
static let DBG_BASIC =     0x001   // basic logging
static let DBG_INFO =      0x002   // more detailed info
static let DBG_MDNS =      0x004   // MDNS related
static let DBG_MDNS_FIND = 0x008   // Show MDNS device discovery
static let DBG_BT =        0x010   // Bluetooth
static let DBG_BT_PACKET = 0x020   // Bluetooth detail packets (very verbose)
static let DBG_WEB =       0x040   // WebKit
static let DBG_PROBE =     0x080   // Log probing
static let DBG_ALERT =     0x100   // Alert service logging
static let DBG_DELAY =     0x1000  // not for logging, enable network debugging

static let DBG_VERBOSE =   0x0ff
static let DBG_DEFAULT =   (DBG_BASIC | DBG_INFO |
                            DBG_MDNS | DBG_MDNS_FIND |
                            DBG_BT |
                            DBG_WEB |
                            DBG_ALERT)

static let PREFIX =     "DDD"

static let LOG_SIZE = 128       // default lines in log buffer
static let LOG_BRIEF = 60       // length of shortened log line to display

static var log_size = LOG_SIZE
static var log_buf = [String?](repeating: nil, count: log_size)
static var log_next = 0
static var log_full = false

static var log_level = DBG_DEFAULT

//  setup: initialize the log buffer
//
static func setup(_ size: Int)
{

    log_size = size
    log_next = 0
    log_full = false
    log_buf = [String?](repeating: nil, count: log_size)
}

//  size: return number of log entries in the buffer
//
static func size() -> Int
{

    return log_full ? log_size : log_next
}

//  get: get log entry for index
//
static func get(_ idx: Int) -> String
{

    var i = idx
    if (log_full) {
        i += log_next
        if (i >= log_size) {
            i -= log_size
        }
    }
    return log_buf[i] ?? ""
}

//  save: add an entry to the log buffer
//
//    Once the buffer is filled the oldest entry is removed\
//    as a new entry is added
//
static func save(_ fmt: String)
{

    log_buf[log_next] = fmt
    log_next += 1
    if (log_next >= log_size) {
        log_next = 0
        log_full = true
    }
}

// l: show debug log line based upon debug level
//
static func l(_ lvl: Int, tag: String, fmt: String)
{

    if ((lvl & log_level) != 0) {
        //  NSLog adds timestamp, print doesn't
        let dfmt = DateFormatter()
        dfmt.dateFormat = "HH:mm:ss" // 24-hour format
        let ts = dfmt.string(from: Date())
        Swift.print(tag + "[" + ts + "] " + fmt)
        //NSLog(tag + ":" + fmt)
        save(tag + ":" + fmt)
    }
}

//  l: overload function, default tag is DDD
//
static func l(_ lvl: Int, _ fmt: String)
{
    var tag: String

    if ((lvl & DBG_MDNS) != 0) {
        tag = "DDD-MDNS"
    } else if ((lvl & DBG_MDNS_FIND) != 0) {
        tag = "DDD-MDNS"
    } else if ((lvl & DBG_BT) != 0) {
        tag = "DDD-BT"
    } else if ((lvl & DBG_WEB) != 0) {
        tag = "DDD-WEB"
    } else if ((lvl & DBG_ALERT) != 0) {
        tag = "DDD-ALERT"
    } else if ((lvl & DBG_INFO) != 0) {
        tag = "DDD"
    } else if ((lvl & DBG_BASIC) != 0) {
        tag = "DDD"
    } else {
        return
    }
    l(lvl, tag: tag, fmt: fmt)
}

//  l: overload, default tag DDD, default level DBG_BASIC
//
static func l(_ fmt: String)
{

    l(DBG_BASIC, tag: PREFIX, fmt: fmt)
}

// d: show debug log line
//
//  Obsolete, all references should be converted to Log.l()
//
//    Print the string fmt and save it into the buffer
//
static func d(_ pre: String, fmt: String)
{

    l(DBG_BASIC, tag: pre, fmt: fmt)
}

// d: overload, default tag DDD
//
//  Obsolete, all references should be converted to l()
//
//    Print the string fmt and save it into the buffer
//
static func d(_ fmt: String)
{
 
    l(DBG_BASIC, tag: PREFIX, fmt: fmt)
}

static func pr_events(_ events: [ String: String ])
{

    for (key, val) in events {
        l("    " + key + ": " + val);
    }
}

static func pr_days(_ days: [ String: Any ])
{

    let date = days["date"]
    l("date:" + (date as! String))
    let events: [ [ String: String] ] = days["events"] as! [ [ String: String] ]
    for event in events {
        pr_events(event)
    }
}

static func pr_itin(_ it: [ String: Any ])
{

    let wh = it["where"]
    l("where:" + (wh as! String))
    let days: [ [ String: Any] ] = it["days"] as! [ [ String: Any] ]
    for day in days {
        pr_days(day)
    }
}

}
