package utils

import (
	"encoding/json"
	"errors"
	"reflect"
	"strconv"
)

func ToString(v interface{}) string {
	//val := reflect.ValueOf(v)
	switch v.(type) {
	case uint:
		return strconv.FormatUint(uint64(v.(uint)), 10)

	case int:
		return strconv.FormatInt(int64(v.(int)), 10)

	case float64:
		return strconv.FormatFloat(float64(v.(float64)), 'f', -1, 64)

	case float32:
		return strconv.FormatFloat(float64(v.(float32)), 'f', -1, 64)

	case string:
		return string(v.(string))

	case bool:
		return strconv.FormatBool(bool(v.(bool)))

	default:
		by, err := json.Marshal(v)
		if err == nil {
			return string(by)
		} else {
			return ""
		}
	}
}

func StringStore(s string, val interface{}) error {
	kd := reflect.TypeOf(val).Elem().Kind()
	va := reflect.ValueOf(val).Elem()
	switch kd {
	case reflect.Bool:
		bl, err := strconv.ParseBool(s)
		if err == nil {
			va.SetBool(bl)
		} else {
			return err
		}

	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		it, err := strconv.ParseInt(s, 10, 64)
		if err == nil {
			va.SetInt(it)
		} else {
			return err
		}

	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		tmp, err := strconv.ParseUint(s, 10, 64)
		if err == nil {
			va.SetUint(tmp)
		} else {
			return err
		}

	case reflect.Float32, reflect.Float64:
		tmp, err := strconv.ParseFloat(s, 64)
		if err == nil {
			va.SetFloat(tmp)
		} else {
			return err
		}

	case reflect.String:
		va.SetString(s)

		return nil

	case reflect.Struct:
		err := json.Unmarshal([]byte(s), val)
		if err != nil {
			return err
		}

	default:
		return errors.New("Unknow type " + kd.String())
	}

	return nil
}

func Angle2LedNo(angle int, totalLeds int, diffled float32, revert bool) int {
	if angle > 360 {
		angle = 360
	}
	dur := float32(360) / float32(totalLeds+1)
	no := int(float32(angle)/(dur) + 0.5 + diffled)
	if no > (totalLeds + 1) {
		no = no - (totalLeds + 1)
	}

	if no == (totalLeds + 1) {
		no = 1
	}

	if revert {
		no = totalLeds + 1 - no
	}

	return no
}

func Angle2LedNo2(angle int, totalLeds int, zeroAngleLed int, sameDirection bool) int {
	if angle > 360 {
		angle = 360
	}
	dur := float32(360) / float32(totalLeds+1)
	diff := int(float32(angle)/(dur) + 0.5)
	no := 0

	if sameDirection == false {
		no = zeroAngleLed - diff
	} else {
		no = diff + zeroAngleLed
	}

	if no < 0 {
		no = no + totalLeds
	}

	if no > totalLeds {
		no = no - totalLeds
	}

	if no == 0 {
		no = totalLeds
	}

	return no
}
