package is31fl3732a

import (
	"errors"
	"fmt"
	"netease_control_center/interfaces/log"
	"netease_control_center/nembd/base"
	"os"
	"sync"
	"syscall"
	"time"
	"unsafe"
)

/*
#include<stddef.h>
	const unsigned char gImage_11[81] = {
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0X00,0X00,0X00,0XFF,
0XFF,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0XFF,
0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00};
	const unsigned char gImage_12[81] = {
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XDB,0X92,0X00,0X00,0X00,0X92,
0XDB,0X00,0XDB,0X92,0X6D,0X24,0X00,0X24,0X6D,0X92,0XDB,0X92,0X6D,0X24,0X24,0X6D,
0X24,0X24,0X6D,0X92,0X00,0X24,0X24,0X6D,0X92,0X6D,0X24,0X24,0X00,0X00,0X00,0X24,
0X6D,0X92,0X6D,0X24,0X00,0X00,0X00,0X00,0X00,0X24,0X6D,0X24,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X24,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00};

extern const unsigned char gImage_heart_1[81];
extern const unsigned char gImage_heart_2[81];
extern const unsigned char gImage_heart_3[81];
extern const unsigned char gImage_heart_4[81];
extern const unsigned char gImage_heart_5[81];
extern const unsigned char gImage_heart_6[81];
extern const unsigned char gImage_heart_7[81];
extern const unsigned char gImage_heart_8[81];
extern const unsigned char gImage_heart_9[81];

extern const unsigned char gImage_heart_10[81];
extern const unsigned char gImage_heart_11[81];
extern const unsigned char gImage_heart_12[81];
extern const unsigned char gImage_heart_13[81];
extern const unsigned char gImage_heart_14[81];
extern const unsigned char gImage_heart_15[81];
extern const unsigned char gImage_heart_16[81];
extern const unsigned char gImage_heart_17[81];
extern const unsigned char gImage_heart_18[81];
extern const unsigned char gImage_heart_19[81];

extern const unsigned char gImage_heart_20[81];
extern const unsigned char gImage_heart_21[81];
extern const unsigned char gImage_heart_22[81];
extern const unsigned char gImage_heart_23[81];
extern const unsigned char gImage_heart_24[81];
extern const unsigned char gImage_heart_25[81];
extern const unsigned char gImage_heart_26[81];
extern const unsigned char gImage_heart_27[81];
extern const unsigned char gImage_heart_28[81];
extern const unsigned char gImage_heart_29[81];

extern const unsigned char gImage_heart_30[81];
extern const unsigned char gImage_heart_31[81];
extern const unsigned char gImage_heart_32[81];
extern const unsigned char gImage_heart_33[81];
extern const unsigned char gImage_heart_34[81];
extern const unsigned char gImage_heart_35[81];
extern const unsigned char gImage_heart_36[81];


*/
import "C"

const (
	devpath        string = "/dev/is31fl3732a"
	MAGIC_NUM             = 'I'
	CMD_ON_OFF            = 0
	CMD_BRIGHTNESS        = 1
	CMD_SET_FRAME         = 2

	MAX_COLS = 16
	MAX_ROWS = 9

	X_OFFSET = 3
)

type IS31FL3732A struct {
	Rows       int
	Cols       int
	initialise bool
	lock       sync.RWMutex
	fd         *os.File
}

func New(Rows int, Cols int) *IS31FL3732A {
	return &IS31FL3732A{
		Rows:       Rows,
		Cols:       Cols,
		initialise: false,
	}
}

func (this *IS31FL3732A) Init() {
	if this.initialise {
		return
	}
	this.lock.Lock()
	defer this.lock.Unlock()

	if !this.initialise {
		fd, ok := os.OpenFile(devpath, os.O_RDWR, os.ModeExclusive)
		if ok == nil {
			this.fd = fd
			this.initialise = true
		} else {
			log.Printf(log.WarningLog, "open faild\n")
		}
	}
}

func (this *IS31FL3732A) sendCmd(command uint32, arg uintptr) error {
	this.Init()
	this.lock.Lock()
	defer this.lock.Unlock()

	cmd := base.IOW(MAGIC_NUM, command, 4)
	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, this.fd.Fd(), uintptr(cmd), uintptr(arg))

	if err != 0 {
		return syscall.Errno(err)
	}
	return nil
}

func (this *IS31FL3732A) On() error {
	this.Init()
	return this.sendCmd(CMD_ON_OFF, 1)
}

func (this *IS31FL3732A) Off() error {
	this.Init()

	return this.sendCmd(CMD_ON_OFF, 0)
}

func (this *IS31FL3732A) SetBtrightness(lev int) error {
	this.Init()
	if lev > 255 {
		lev = 255
	}

	return this.sendCmd(CMD_BRIGHTNESS, uintptr(lev))
}

func (this *IS31FL3732A) ShowFrame(data *[]byte) error {
	this.Init()

	return this.sendCmd(CMD_SET_FRAME, uintptr(unsafe.Pointer(&data)))
}

func (this *IS31FL3732A) Lightall() error {
	this.Init()

	data := new([9][16]byte)
	for k1, _ := range data {
		for k2, _ := range data[k1] {
			if k2 == 6 {
				data[k1][k2] = 0xff
			} else {
				data[k1][k2] = 0x0
			}
		}
		fmt.Println(k1, data[k1])
	}

	return this.sendCmd(CMD_SET_FRAME, uintptr(unsafe.Pointer(data)))
}

func (this *IS31FL3732A) Show(startX int, startY int, numX int, numY int, data *[]byte) error {
	if numX*numY > len(*data) {
		return errors.New("not enough dots")
	}

	buf := new([MAX_ROWS][MAX_COLS]byte)
	startX = startX + X_OFFSET

	for y := startY; y < (startY+numY) && y < MAX_ROWS; y = y + 1 {
		for x := startX; x < (startX+numX) && x < MAX_COLS; x = x + 1 {
			buf[y][x] = (*data)[x-startX+(y-startY)*numX]
		}
		//fmt.Println(y, buf[y])
	}

	return this.sendCmd(CMD_SET_FRAME, uintptr(unsafe.Pointer(buf)))
}

func (this *IS31FL3732A) Show2(startX int, startY int, numX int, numY int, data *[][]byte) error {
	if numX*numY > len(*data)*len((*data)[0]) {
		return errors.New("not enough dots")
	}

	buf := new([MAX_ROWS][MAX_COLS]byte)

	for y := startY; y < (startY+numY) && y < MAX_ROWS; y = y + 1 {
		for x := startX; x < (startX+numX) && x < MAX_COLS; x = x + 1 {
			buf[y][x+X_OFFSET] = (*data)[y][x]
		}
		//fmt.Println(y, buf[y])
	}

	return this.sendCmd(CMD_SET_FRAME, uintptr(unsafe.Pointer(buf)))
}

func (this *IS31FL3732A) Test() {
	buf := make([]byte, 10*10)
	for k, _ := range buf {
		buf[k] = 0xff
	}
	this.Show(0, 0, 9, 9, &buf)
}

func (this *IS31FL3732A) FixedTest() {
	n := 1
	var tt time.Time
	fmt.Println("Begin show new pic", tt)
	for {
		if n == 1 {
			tt = time.Now()
		}
		//buf := C.GoBytes(unsafe.Pointer(&(C.gImage_11[0])), C.int(unsafe.Sizeof(C.gImage_11)))

		//this.Show(0, 0, 9, 9, &buf)
		//time.Sleep(time.Second)
		//buf := C.GoBytes(unsafe.Pointer(&(C.gImage_heart_18[0])), C.int(unsafe.Sizeof(C.gImage_12)))
		//this.Show(0, 0, 9, 9, &buf)
		//time.Sleep(time.Second)
		this.Xshow(n)
		if n = n + 1; n == 37 {
			n = 1
			time.Sleep(2 * time.Second)
			//fmt.Println("Coast time:", tt.Before(time.Now()))
		}
		if n == 13 {
			//break
		}
		time.Sleep(30 * time.Millisecond)
	}
}

func (this *IS31FL3732A) Xshow(n int) {
	var buf []byte
	switch n {
	case 1:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_1[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 2:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_2[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 3:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_3[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 4:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_4[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 5:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_5[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 6:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_6[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 7:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_7[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 8:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_8[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 9:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_9[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 10:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_10[0])), C.int(unsafe.Sizeof(C.gImage_12)))

	case 11:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_11[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 12:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_12[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 13:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_13[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 14:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_14[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 15:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_15[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 16:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_16[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 17:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_17[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 18:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_18[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 19:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_19[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 20:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_20[0])), C.int(unsafe.Sizeof(C.gImage_12)))

	case 21:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_21[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 22:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_22[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 23:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_23[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 24:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_24[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 25:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_25[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 26:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_26[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 27:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_27[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 28:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_28[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 29:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_29[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 30:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_30[0])), C.int(unsafe.Sizeof(C.gImage_12)))

	case 31:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_31[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 32:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_32[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 33:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_33[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 34:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_34[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 35:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_35[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	case 36:
		buf = C.GoBytes(unsafe.Pointer(&(C.gImage_heart_36[0])), C.int(unsafe.Sizeof(C.gImage_12)))
	}

	this.Show(0, 0, 9, 9, &buf)
}
