//
//  tank
//
//  Import and Playlist Daemon for autoradio project
//
//
//  Copyright (C) 2017-2019 Christian Pointner <equinox@helsinki.at>
//
//  This file is part of tank.
//
//  tank is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  any later version.
//
//  tank is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with tank. If not, see <http://www.gnu.org/licenses/>.
//

package store

import (
	"errors"
	"fmt"
	"os"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
	_ "github.com/jinzhu/gorm/dialects/postgres"
	// _ "github.com/jinzhu/gorm/dialects/sqlite"
	// _ "github.com/jinzhu/gorm/dialects/mssql"
)

type Store struct {
	revision string
	db       *gorm.DB
	basePath string
	Audio    AudioConfig
}

//
// Initialization and Destruction
//

func mysqlConnectionString(cfg DBConfig) (conn string) {
	// "tank:aura@tcp(127.0.0.1:3306)/tank?charset=utf8&parseTime=True&loc=Local"
	conn = cfg.Username
	if cfg.Password != "" {
		conn += ":" + cfg.Password
	}
	if cfg.Port > 0 {
		conn += fmt.Sprintf("@tcp(%s:%d)", cfg.Host, cfg.Port)
	} else {
		conn += "@tcp(" + cfg.Host + ")"
	}
	conn += "/" + cfg.DB + "?parseTime=True&loc=Local"

	if cfg.TLS != "" {
		conn += "&tls=" + cfg.TLS
	}
	return
}

func postgresConnectionString(cfg DBConfig) (conn string) {
	// "host=127.0.0.1 port=5432 user=tank password=aura dbname=tank sslmode=disable"
	conn = "host=" + cfg.Host
	if cfg.Port > 0 {
		conn += fmt.Sprintf(" port=%d", cfg.Port)
	}
	conn += " user=" + cfg.Username
	if cfg.Password != "" {
		conn += " password=" + cfg.Password
	}
	conn += " dbname=" + cfg.DB
	if cfg.TLS != "" {
		conn += " sslmode=" + cfg.TLS
	}
	return
}

func openDB(cfg DBConfig) (db *gorm.DB, err error) {
	var conn string
	switch cfg.Type {
	case "mysql":
		conn = mysqlConnectionString(cfg)
	case "postgres":
		conn = postgresConnectionString(cfg)
	default:
		return nil, errors.New("unknown database engine: " + cfg.Type)
	}

	if db, err = gorm.Open(cfg.Type, conn); err != nil {
		return nil, errors.New("gorm.open(): " + err.Error())
	}

	db.LogMode(cfg.Debug)
	if err = db.DB().Ping(); err != nil {
		return nil, errors.New("gorm.Ping(): " + err.Error())
	}

	return
}

func NewStore(cfg Config) (*Store, error) {
	if _, err := os.Stat(cfg.BasePath); err != nil {
		return nil, errors.New("cant't open store's base path: " + err.Error())
	}

	db, err := openDB(cfg.DB)
	if err != nil {
		return nil, err
	}

	st := &Store{"", db, cfg.BasePath, cfg.Audio}
	if err = st.initDBModel(); err != nil {
		return nil, err
	}

	if _, err = st.CreateGroup(publicGroupName); err != nil {
		return nil, err
	}

	return st, nil
}

func (st *Store) GetRevision() string {
	return st.revision
}

func (st *Store) Close() {
	st.db.Close()
}