/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package config

import (
	log "github.com/Sirupsen/logrus"
	"github.com/mitchellh/go-homedir"

	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"

	"mynewt.apache.org/newt/util"
	"mynewt.apache.org/newtmgr/newtmgr/nmutil"
)

type ConnProfileMgr struct {
	profiles map[string]*ConnProfile
}

type ConnType int

type ConnProfile struct {
	Name       string   `json:"MyName"`
	Type       ConnType `json:"MyType"`
	ConnString string   `json:"MyConnString"`
}

func (p *ConnProfile) String() string {
	return fmt.Sprintf("name=%s type=%s connstring=%s",
		p.Name, ConnTypeToString(p.Type), p.ConnString)
}

const (
	CONN_TYPE_NONE ConnType = iota
	CONN_TYPE_SERIAL_PLAIN
	CONN_TYPE_SERIAL_OIC
	CONN_TYPE_BLL_PLAIN
	CONN_TYPE_BLL_OIC
	CONN_TYPE_BLE_PLAIN
	CONN_TYPE_BLE_OIC
	CONN_TYPE_UDP_PLAIN
	CONN_TYPE_UDP_OIC
	CONN_TYPE_MTECH_LORA_OIC
)

var connTypeNameMap = map[ConnType]string{
	CONN_TYPE_SERIAL_PLAIN:   "serial",
	CONN_TYPE_SERIAL_OIC:     "oic_serial",
	CONN_TYPE_BLL_PLAIN:      "ble",
	CONN_TYPE_BLL_OIC:        "oic_ble",
	CONN_TYPE_BLE_PLAIN:      "bhd",
	CONN_TYPE_BLE_OIC:        "oic_bhd",
	CONN_TYPE_UDP_PLAIN:      "udp",
	CONN_TYPE_UDP_OIC:        "oic_udp",
	CONN_TYPE_MTECH_LORA_OIC: "oic_mtech",
	CONN_TYPE_NONE:           "???",
}

func ConnTypeToString(ct ConnType) string {
	return connTypeNameMap[ct]
}

func ConnTypeFromString(s string) (ConnType, error) {
	for k, v := range connTypeNameMap {
		if s == v {
			return k, nil
		}
	}

	return ConnType(0), util.FmtNewtError("Invalid connection type: %s", s)
}

func (t *ConnType) MarshalJSON() ([]byte, error) {
	return json.Marshal(ConnTypeToString(*t))
}

func (ct *ConnType) UnmarshalJSON(data []byte) error {
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}

	var err error
	*ct, err = ConnTypeFromString(s)
	if err != nil {
		*ct = CONN_TYPE_NONE
	}
	return nil
}

func NewConnProfileMgr() (*ConnProfileMgr, error) {
	cpm := &ConnProfileMgr{
		profiles: map[string]*ConnProfile{},
	}

	if err := cpm.Init(); err != nil {
		return nil, err
	}

	return cpm, nil
}

func connProfileCfgFilename() (string, error) {
	dir, err := homedir.Dir()
	if err != nil {
		return "", util.NewNewtError(err.Error())
	}

	return filepath.Join(dir, nmutil.ToolInfo.CfgFilename), nil
}

func (cpm *ConnProfileMgr) Init() error {
	filename, err := connProfileCfgFilename()
	if err != nil {
		return err
	}

	log.Debugf("Reading connection profiles from %s", filename)
	blob, err := ioutil.ReadFile(filename)
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		} else {
			return util.ChildNewtError(err)
		}
	}

	var profiles []*ConnProfile
	if err := json.Unmarshal(blob, &profiles); err != nil {
		return util.FmtNewtError("error reading connection profile "+
			"config (%s): %s", filename, err.Error())
	}

	for _, p := range profiles {
		cpm.profiles[p.Name] = p
	}

	return nil
}

type connProfSorter struct {
	cps []*ConnProfile
}

func (s connProfSorter) Len() int {
	return len(s.cps)
}
func (s connProfSorter) Swap(i, j int) {
	s.cps[i], s.cps[j] = s.cps[j], s.cps[i]
}
func (s connProfSorter) Less(i, j int) bool {
	return s.cps[i].Name < s.cps[j].Name
}

func SortConnProfs(cps []*ConnProfile) []*ConnProfile {
	sorter := connProfSorter{
		cps: make([]*ConnProfile, 0, len(cps)),
	}

	for _, p := range cps {
		sorter.cps = append(sorter.cps, p)
	}

	sort.Sort(sorter)
	return sorter.cps
}

func (cpm *ConnProfileMgr) GetConnProfileList() ([]*ConnProfile, error) {
	log.Debugf("Getting list of connection profiles")

	cpList := make([]*ConnProfile, 0, len(cpm.profiles))
	for _, p := range cpm.profiles {
		cpList = append(cpList, p)
	}

	return SortConnProfs(cpList), nil
}

func (cpm *ConnProfileMgr) save() error {
	list, _ := cpm.GetConnProfileList()
	b, err := json.MarshalIndent(list, "", "    ")
	if err != nil {
		return util.NewNewtError(err.Error())
	}

	filename, err := connProfileCfgFilename()
	if err != nil {
		return err
	}

	err = ioutil.WriteFile(filename, b, 0644)
	if err != nil {
		return util.ChildNewtError(err)
	}

	return nil
}

func (cpm *ConnProfileMgr) DeleteConnProfile(name string) error {
	if cpm.profiles[name] == nil {
		return util.FmtNewtError("connection profile \"%s\" doesn't exist",
			name)
	}

	delete(cpm.profiles, name)

	err := cpm.save()
	if err != nil {
		return err
	}

	return nil
}

func (cpm *ConnProfileMgr) AddConnProfile(cp *ConnProfile) error {
	cpm.profiles[cp.Name] = cp

	err := cpm.save()
	if err != nil {
		return err
	}

	return nil
}

func (cpm *ConnProfileMgr) GetConnProfile(pName string) (*ConnProfile, error) {
	// Each section is a connection profile, key values are the contents
	// of that section.
	p := cpm.profiles[pName]
	if p == nil {
		return nil, util.FmtNewtError("connection profile \"%s\" doesn't "+
			"exist", pName)
	}

	return p, nil
}

func NewConnProfile() *ConnProfile {
	return &ConnProfile{}
}

var globalConnProfileMgr *ConnProfileMgr

func GlobalConnProfileMgr() *ConnProfileMgr {
	if globalConnProfileMgr == nil {
		panic("connection profile manager not initialized")
	}
	return globalConnProfileMgr
}

func InitGlobalConnProfileMgr() error {
	if globalConnProfileMgr != nil {
		return util.NewNewtError("connection profile manager initialized twice")
	}

	var err error
	globalConnProfileMgr, err = NewConnProfileMgr()
	if err != nil {
		return err
	}

	return nil
}
