package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
)

// Board def
type Board struct {
	ChannelCount uint   `json:"channelcount"`
	ID           string `json:"id"`
	Name         string `json:"name"`
	Type         string `json:"type"`
	Bus          uint   `json:"bus"`
	Address      uint   `json:"address"`
}

// ChannelName - return the name of a channel, useful for onboard GPIO
func (b Board) ChannelName(num uint) string {
	return string(num)
}

// PowerON def
func (b Board) PowerON(num uint) error {
	return nil
}

// PowerOFF def
func (b Board) PowerOFF(num uint) error {
	return nil
}

// PowerToggle def
func (b Board) PowerToggle(num uint) error {
	return nil
}

// Boardlink def
type Boardlink struct {
	BoardID string `json:"boardid"`
	Channel uint   `json:"channel"`
	board   Board
}

// Board def
func (bl Boardlink) Board() Board {
	fmt.Printf("\n boardlink: \n\n")
	if bl.board.ID == "" {
		fmt.Printf("\n board nil: \n\n")
		for i := range TheConfig.Boards {
			if TheConfig.Boards[i].ID == bl.BoardID {
				bl.board = TheConfig.Boards[i]
				break
			}
		}
	}
	return bl.board
}

// PowerON def
func (bl Boardlink) PowerON() error {
	return bl.Board().PowerON(bl.Channel)
}

// PowerOFF def
func (bl Boardlink) PowerOFF() error {
	return bl.Board().PowerOFF(bl.Channel)
}

// PowerToggle def
func (bl Boardlink) PowerToggle() error {
	return bl.Board().PowerToggle(bl.Channel)
}

// Outlet def
type Outlet struct {
	Name          string    `json:"name"`
	Location      string    `json:"location"`
	HasPowerMeter bool      `json:"haspowermeter"`
	Command       Boardlink `json:"command"`
	PowerMeter    Boardlink `json:"powermeter"`
}

// PowerON def
func (o Outlet) PowerON() error {
	return o.Command.PowerON()
}

// PowerOFF def
func (o Outlet) PowerOFF() error {
	return o.Command.PowerOFF()
}

// PowerToggle def
func (o Outlet) PowerToggle() error {
	return o.Command.PowerToggle()
}

// MQTTConfig def
type MQTTConfig struct {
	BrokerIP      string `json:"ip"`
	BrokerPort    string `json:"port"`
	ClientID      string `json:"clientid"`
	Username      string `json:"username"`
	Password      string `json:"password"`
	CleanSession  bool   `json:"cleansession"`
	Topic         string `json:"topic"`
	HomeAssistant bool   `json:"homeassistant"`
}

// Configuration def
type Configuration struct {
	Hostname string            `json:"hostname"`
	Outlets  map[(uint)]Outlet `json:"outlets"`
	Boards   []Board           `json:"boards"`
	MQTT     MQTTConfig        `json:"mqtt"`
}

func loadConfig(filename string) (Configuration, error) {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		return Configuration{}, err
	}

	var c Configuration
	err = json.Unmarshal(bytes, &c)
	if err != nil {
		return Configuration{}, err
	}

	return c, nil
}

func saveConfig(c Configuration, filename string) error {
	bytes, err := json.MarshalIndent(c, "", "  ")
	if err != nil {
		return err
	}

	return ioutil.WriteFile(filename, bytes, 0644)
}

// TheConfig def
var TheConfig Configuration

func main() {
	var err error

	var c1 Configuration

	c1 = createMockConfig()
	for n, br := range c1.Boards {
		fmt.Printf("A - Board %v (%v)\n", n, br.Type)
	}

	err = saveConfig(c1, "t.json")
	if err != nil {
		panic(err)
	}

	TheConfig, err = loadConfig("t.json")
	if err != nil {
		panic(err)
	}

	err = saveConfig(TheConfig, "t1.json")
	if err != nil {
		panic(err)
	}

	fmt.Printf("\n\nmqtt: %v\n\n", TheConfig.MQTT)

	TheConfig.Outlets[0].PowerON()
}

func createMockConfig() Configuration {
	return Configuration{
		Hostname: "maramao",
		MQTT: MQTTConfig{
			BrokerIP:      "192.168.2.190",
			BrokerPort:    "1883",
			ClientID:      "openpdu-123",
			Username:      "DVES_USER",
			Password:      "DVES_PASS",
			CleanSession:  false,
			Topic:         "openpdu/ok",
			HomeAssistant: true,
		},
		Boards: []Board{
			Board{
				ID:           "6561df75-bf93-43f5-82ac-9b3dda081961",
				Name:         "Internal GPIO",
				Type:         "GPIO",
				ChannelCount: 40,
			},
			Board{
				Bus:          1,
				Address:      0x29,
				ID:           "79690164-214f-41b0-93f9-e910dd54f323",
				Name:         "bordo1",
				Type:         "I2C-GPIO",
				ChannelCount: 8,
			},
			Board{
				Bus:          1,
				Address:      0x27,
				ID:           "93f446d8-59e4-4abd-8bf7-e31cd80bc713",
				Name:         "bordo2",
				Type:         "I2C-ADC",
				ChannelCount: 4,
			},
		},
		Outlets: map[(uint)]Outlet{
			0: Outlet{
				Name:          "uscita 0",
				Location:      "port 1 dx",
				HasPowerMeter: true,
				Command: Boardlink{
					BoardID: "79690164-214f-41b0-93f9-e910dd54f323",
					Channel: 0,
				},
				PowerMeter: Boardlink{
					BoardID: "93f446d8-59e4-4abd-8bf7-e31cd80bc713",
					Channel: 0,
				},
			},
			1: Outlet{
				Name:          "uscita 1",
				Location:      "port 1 sx",
				HasPowerMeter: true,
				Command: Boardlink{
					BoardID: "79690164-214f-41b0-93f9-e910dd54f323",
					Channel: 1,
				},
				PowerMeter: Boardlink{
					BoardID: "93f446d8-59e4-4abd-8bf7-e31cd80bc713",
					Channel: 1,
				},
			},
			2: Outlet{
				Name:          "uscita 2",
				Location:      "port 2 dx",
				HasPowerMeter: false,
				Command: Boardlink{
					BoardID: "79690164-214f-41b0-93f9-e910dd54f323",
					Channel: 2,
				},
			},
			3: Outlet{
				Name:          "uscita 5v 1",
				Location:      "usb avanti 1",
				HasPowerMeter: false,
				Command: Boardlink{
					BoardID: "6561df75-bf93-43f5-82ac-9b3dda081961",
					Channel: 21,
				},
			},
			4: Outlet{
				Name:          "uscita 5v 2",
				Location:      "usb avanti 2",
				HasPowerMeter: false,
				Command: Boardlink{
					BoardID: "6561df75-bf93-43f5-82ac-9b3dda081961",
					Channel: 22,
				},
			},
		},
	}
}
