/* Copyright (c) 2018, joy.zhou <chowyu08@gmail.com>
 */
package acl

import (
	"bufio"
	"errors"
	"io"
	"os"
	"strconv"
	"strings"
)

const (
	PUB      = 1
	SUB      = 2
	PUBSUB   = 3
	CLIENTID = "clientid"
	USERNAME = "username"
	IP       = "ip"
	ALLOW    = "allow"
	DENY     = "deny"
)

type AuthInfo struct {
	Auth   string
	Typ    string
	Val    string
	PubSub int
	Topics []string
}

type ACLConfig struct {
	File string
	Info []*AuthInfo
}

func AclConfigLoad(file string) (*ACLConfig, error) {
	if file == "" {
		file = "./conf/acl.conf"
	}
	aclconifg := &ACLConfig{
		File: file,
		Info: make([]*AuthInfo, 0, 4),
	}
	err := aclconifg.Prase()
	if err != nil {
		return nil, err
	}
	return aclconifg, err
}

func (c *ACLConfig) Prase() error {
	f, err := os.Open(c.File)
	defer f.Close()
	if err != nil {
		return err
	}
	buf := bufio.NewReader(f)
	var parseErr error
	for {
		line, err := buf.ReadString('\n')
		line = strings.TrimSpace(line)
		if isCommentOut(line) {
			continue
		}
		if line == "" {
			return parseErr
		}
		// fmt.Println(line)
		tmpArr := strings.Fields(line)
		if len(tmpArr) != 5 {
			parseErr = errors.New("\"" + line + "\" format is error")
			break
		}
		if tmpArr[0] != ALLOW && tmpArr[0] != DENY {
			parseErr = errors.New("\"" + line + "\" format is error")
			break
		}
		if tmpArr[1] != CLIENTID && tmpArr[1] != USERNAME && tmpArr[1] != IP {
			parseErr = errors.New("\"" + line + "\" format is error")
			break
		}
		var pubsub int
		pubsub, err = strconv.Atoi(tmpArr[3])
		if err != nil {
			parseErr = errors.New("\"" + line + "\" format is error")
			break
		}
		topicStr := strings.Replace(tmpArr[4], " ", "", -1)
		topicStr = strings.Replace(topicStr, "\n", "", -1)
		topics := strings.Split(topicStr, ",")
		tmpAuth := &AuthInfo{
			Auth:   tmpArr[0],
			Typ:    tmpArr[1],
			Val:    tmpArr[2],
			Topics: topics,
			PubSub: pubsub,
		}
		c.Info = append(c.Info, tmpAuth)
		if err != nil {
			if err != io.EOF {
				parseErr = err
			}
			break
		}
	}
	return parseErr
}
func isCommentOut(line string) bool {
	if strings.HasPrefix(line, "#") || strings.HasPrefix(line, ";") || strings.HasPrefix(line, "//") || strings.HasPrefix(line, "*") {
		return true
	} else {
		return false
	}
}
