package ccolor

import (
	
	
	
)

// Color Color16, 16 color value type
// 3(2^3=8) OR 4(2^4=16) bite color.
type Color uint8

/*************************************************************
 * Basic 16 color definition
 *************************************************************/

// Boundary value for foreground/background color 16
//
//   - base: fg 30~37, bg 40~47
//   - light: fg 90~97, bg 100~107
const (
	fgBase uint8 = 30
	fgMax  uint8 = 37
	bgBase uint8 = 40
	bgMax  uint8 = 47

	hiFgBase uint8 = 90
	hiFgMax  uint8 = 97
	hiBgBase uint8 = 100
	hiBgMax  uint8 = 107

	// optMax max option value. range: 0 - 9
	optMax = 10
)

// Foreground colors. basic foreground colors 30 - 37
const (
	FgBlack Color = iota + 30
	FgRed
	FgGreen
	FgYellow
	FgBlue
	FgMagenta // 品红
	FgCyan    // 青色
	FgWhite
	// FgDefault revert default FG
	FgDefault Color = 39
)

// Extra foreground color 90 - 97(非标准)
const (
	FgDarkGray Color = iota + 90 // 亮黑(灰)
	FgLightRed
	FgLightGreen
	FgLightYellow
	FgLightBlue
	FgLightMagenta
	FgLightCyan
	FgLightWhite
	// FgGray is alias of FgDarkGray
	FgGray Color = 90 // 亮黑(灰)
)

// Background colors. basic background colors 40 - 47
const (
	BgBlack Color = iota + 40
	BgRed
	BgGreen
	BgYellow // BgBrown like yellow
	BgBlue
	BgMagenta
	BgCyan
	BgWhite
	// BgDefault revert default BG
	BgDefault Color = 49
)

// Extra background color 100 - 107 (non-standard)
const (
	BgDarkGray Color = iota + 100
	BgLightRed
	BgLightGreen
	BgLightYellow
	BgLightBlue
	BgLightMagenta
	BgLightCyan
	BgLightWhite
	// BgGray is alias of BgDarkGray
	BgGray Color = 100
)

// Option settings. range: 0 - 9
const (
	OpReset         Color = iota // 0 重置所有设置
	OpBold                       // 1 加粗
	OpFuzzy                      // 2 模糊(不是所有的终端仿真器都支持)
	OpItalic                     // 3 斜体(不是所有的终端仿真器都支持)
	OpUnderscore                 // 4 下划线
	OpBlink                      // 5 闪烁
	OpFastBlink                  // 6 快速闪烁(未广泛支持)
	OpReverse                    // 7 颠倒的 交换背景色与前景色
	OpConcealed                  // 8 隐匿的
	OpStrikethrough              // 9 删除的,删除线(未广泛支持)
)

// There are basic and light foreground color aliases
const (
	Red     = FgRed
	Cyan    = FgCyan
	Gray    = FgDarkGray // is light Black
	Blue    = FgBlue
	Black   = FgBlack
	Green   = FgGreen
	White   = FgWhite
	Yellow  = FgYellow
	Magenta = FgMagenta

	// special

	Bold   = OpBold
	Normal = FgDefault

	// extra light

	LightRed     = FgLightRed
	LightCyan    = FgLightCyan
	LightBlue    = FgLightBlue
	LightGreen   = FgLightGreen
	LightWhite   = FgLightWhite
	LightYellow  = FgLightYellow
	LightMagenta = FgLightMagenta

	HiRed     = FgLightRed
	HiCyan    = FgLightCyan
	HiBlue    = FgLightBlue
	HiGreen   = FgLightGreen
	HiWhite   = FgLightWhite
	HiYellow  = FgLightYellow
	HiMagenta = FgLightMagenta

	BgHiRed     = BgLightRed
	BgHiCyan    = BgLightCyan
	BgHiBlue    = BgLightBlue
	BgHiGreen   = BgLightGreen
	BgHiWhite   = BgLightWhite
	BgHiYellow  = BgLightYellow
	BgHiMagenta = BgLightMagenta
)

/*************************************************************
 * Color render methods
 *************************************************************/

// Text render a text message
func ( Color) ( string) string { return RenderString(.String(), ) }

// Render messages by color setting
//
// Usage:
//
//	green := ccolor.FgGreen.Render
//	fmt.Println(green("message"))
func ( Color) ( ...any) string { return RenderCode(.String(), ...) }

// Renderln messages by color setting.
// like fmt.Println, will add spaces for each argument
//
// Usage:
//
//	green := ccolor.FgGreen.Renderln
//	fmt.Println(green("message"))
func ( Color) ( ...any) string { return RenderWithSpaces(.String(), ...) }

// Sprint render messages by color setting. is alias of the Render()
func ( Color) ( ...any) string { return RenderCode(.String(), ...) }

// Sprintf format and render message.
//
// Usage:
//
//		green := ccolor.Green.Sprintf
//	 	colored := green("message")
func ( Color) ( string,  ...any) string {
	return RenderString(.String(), fmt.Sprintf(, ...))
}

// Print messages.
//
// Usage:
//
//	ccolor.Green.Print("message")
//
// OR:
//
//	green := ccolor.FgGreen.Print
//	green("message")
func ( Color) ( ...any) {
	doPrint(.Code(), fmt.Sprint(...))
}

// Printf format and print messages.
//
// Usage:
//
//	ccolor.Cyan.Printf("string %s", "arg0")
func ( Color) ( string,  ...any) {
	doPrint(.Code(), fmt.Sprintf(, ...))
}

// Println messages with new line
func ( Color) ( ...any) { doPrintln(.String(), ) }

// Fprint writes to w with color setting.
//
// Usage:
//
//	ccolor.Green.Fprint(os.Stdout, "message")
func ( Color) ( io.Writer,  ...any) {
	doPrintTo(, .String(), fmt.Sprint(...))
}

// Fprintf formats and writes to w with color setting.
//
// Usage:
//
//	ccolor.Cyan.Fprintf(os.Stdout, "string %s", "arg0")
func ( Color) ( io.Writer,  string,  ...any) {
	doPrintTo(, .String(), fmt.Sprintf(, ...))
}

// Fprintln writes to w with color setting and adds a new line.
//
// Usage:
//
//	ccolor.Green.Fprintln(os.Stdout, "message")
func ( Color) ( io.Writer,  ...any) {
	doPrintlnTo(, .String(), )
}

// Light current color. eg: 36(FgCyan) -> 96(FgLightCyan).
//
// Usage:
//
//	lightCyan := Cyan.Light()
//	lightCyan.Print("message")
func ( Color) () Color {
	 := uint8()
	if  >= 30 &&  <= 47 {
		return Color( + 60)
	}

	// don't change
	return 
}

// Darken current color. eg. 96(FgLightCyan) -> 36(FgCyan)
//
// Usage:
//
//	cyan := LightCyan.Darken()
//	cyan.Print("message")
func ( Color) () Color {
	 := uint8()
	if  >= 90 &&  <= 107 {
		return Color( - 60)
	}

	// don't change
	return 
}

// ToFg always convert fg
func ( Color) () Color {
	 := uint8()
	// option code, don't change
	if  < 10 {
		return 
	}
	return Color(Bg2Fg())
}

// ToBg always convert bg
func ( Color) () Color {
	 := uint8()
	// option code, don't change
	if  < 10 {
		return 
	}
	return Color(Fg2Bg())
}

// Code convert to code string. eg "35"
func ( Color) () string {
	return strconv.FormatInt(int64(), 10)
}

// String convert to code string. eg "35"
func ( Color) () string {
	return strconv.FormatInt(int64(), 10)
}

// IsBg check is background color
func ( Color) () bool {
	 := uint8()
	return  >= bgBase &&  <= bgMax ||  >= hiBgBase &&  <= hiBgMax
}

// IsFg check is foreground color
func ( Color) () bool {
	 := uint8()
	return  >= fgBase &&  <= fgMax ||  >= hiFgBase &&  <= hiFgMax
}

// IsOption check is option code: 0-9
func ( Color) () bool { return uint8() < optMax }

// IsValid color value
func ( Color) () bool { return uint8() < hiBgMax }

/*************************************************************
 * basic color maps
 *************************************************************/

// FgColors foreground colors map
var FgColors = map[string]Color{
	"black":   FgBlack,
	"red":     FgRed,
	"green":   FgGreen,
	"yellow":  FgYellow,
	"blue":    FgBlue,
	"magenta": FgMagenta,
	"cyan":    FgCyan,
	"white":   FgWhite,
	"default": FgDefault,
}

// BgColors background colors map
var BgColors = map[string]Color{
	"black":   BgBlack,
	"red":     BgRed,
	"green":   BgGreen,
	"yellow":  BgYellow,
	"blue":    BgBlue,
	"magenta": BgMagenta,
	"cyan":    BgCyan,
	"white":   BgWhite,
	"default": BgDefault,
}

// ExFgColors extra foreground colors map
var ExFgColors = map[string]Color{
	"darkGray":     FgDarkGray,
	"lightRed":     FgLightRed,
	"lightGreen":   FgLightGreen,
	"lightYellow":  FgLightYellow,
	"lightBlue":    FgLightBlue,
	"lightMagenta": FgLightMagenta,
	"lightCyan":    FgLightCyan,
	"lightWhite":   FgLightWhite,
}

// ExBgColors extra background colors map
var ExBgColors = map[string]Color{
	"darkGray":     BgDarkGray,
	"lightRed":     BgLightRed,
	"lightGreen":   BgLightGreen,
	"lightYellow":  BgLightYellow,
	"lightBlue":    BgLightBlue,
	"lightMagenta": BgLightMagenta,
	"lightCyan":    BgLightCyan,
	"lightWhite":   BgLightWhite,
}

// AllOptions color options map
var AllOptions = map[string]Color{
	"reset":      OpReset,
	"bold":       OpBold,
	"fuzzy":      OpFuzzy,
	"italic":     OpItalic,
	"underscore": OpUnderscore,
	"blink":      OpBlink,
	"reverse":    OpReverse,
	"concealed":  OpConcealed,
}

// Bg2Fg bg color value to fg value
func ( uint8) uint8 {
	if  >= bgBase &&  <= 47 { // is bg
		 =  - 10
	} else if  >= hiBgBase &&  <= 107 { // is hi bg
		 =  - 10
	}
	return 
}

// Fg2Bg fg color value to bg value
func ( uint8) uint8 {
	if  >= fgBase &&  <= 37 { // is fg
		 =  + 10
	} else if  >= hiFgBase &&  <= 97 { // is hi fg
		 =  + 10
	}
	return 
}