package bx

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"github.com/sirupsen/logrus"
	"time"
)

// 普通文本文件
type bxFile struct {
	type_       byte   //默认0x00
	name        string //4字节ASCII
	len         uint32
	content     string
	Priority    byte
	DisplayType uint16 //播放方式节目播放方式，0——顺序播放，其他——定长播放的 时间，单位为秒
	PlayTimes   byte
	//节目生命周期，发送顺序为：起始年(2)+起始月(1)+起
	//始日(1)+结束年(2)+结束月(1)+结束日(1)注：1. 时间均
	//采用 BCD 码的方式2. 年范围为 0x1900—0x2099，
	//0xffff 为永久有效，先发送 LSB，后发送 MSB
	ProgramLife string
	//节目的星期属性
	//1. Bit0 为 1 表示一周中的每一天都播放。
	//2. Bit0 为 0 时，需判断 bit1-bit7 的来决定每天播放，
	//bit1-bit7依次表示周一到周日。
	//3.比特为0表示禁止播放，为 1 表示播放。
	ProgramWeek byte
	//定时节目位 0 非定时，注：为 0 时则播放时段组数设 置为 0
	ProgramTime byte
	//节目播放时段组数，最多支持一组，当为 0 时 PlayPeriodSetting
	PlayPeriodGrpNum byte
	//6Byte 播放组0，发送顺序为：起始小时(1)+起始分钟(1)+起始秒(1)+结束小时(1)+结束分钟(1)+结束秒(1)
	//PlayPeriodSetting0 time.Time
	Areas []BxArea
}

// NewBxFile diedLine 节目过期时间 "2006-01-02", 传"" 永不过期
func NewBxFile(fileName string, diedLine string, areas []BxArea) bxFile {
	return bxFile{
		name:        fileName,
		Areas:       areas,
		ProgramLife: diedLine,
		Priority:    0xff,
		PlayTimes:   1,
		ProgramWeek: 1,
	}
}
func (f bxFile) NewCmdWriteFile() *CmdWriteFile {
	return &CmdWriteFile{
		baseBxCmd:     newBaseCmd(CMD_WRITE_FILE.group, CMD_WRITE_FILE.code),
		file:          &f,
		LastBlockFlag: 1,
	}
}

func (f bxFile) encodeProgramLife() []byte {
	if f.ProgramLife == "" {
		return []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
	}
	w := bufPoll.Get().(*bytes.Buffer)
	now := time.Now()
	y := Uint2BCD(uint64(now.Year()), false)
	m := Uint2BCD(uint64(now.Month()), false)
	d := Uint2BCD(uint64(now.Day()), false)
	binary.Write(w, binary.BigEndian, y)
	binary.Write(w, binary.BigEndian, m)
	binary.Write(w, binary.BigEndian, d)
	end, err := time.Parse("2006-01-02", f.ProgramLife)
	if err != nil {
		logrus.Error("时间解析错误:", err)
		return nil
	}
	endY := Uint2BCD(uint64(end.Year()), false)
	endM := Uint2BCD(uint64(end.Month()), false)
	endD := Uint2BCD(uint64(end.Day()), false)
	binary.Write(w, binary.BigEndian, endY)
	binary.Write(w, binary.BigEndian, endM)
	binary.Write(w, binary.BigEndian, endD)
	return w.Bytes()
}

//func (f bxFile) Build() []byte {
//	w := bytes.NewBuffer(make([]byte, 0, 1024))
//	return w.Bytes()
//}

type CmdWriteFile struct {
	baseBxCmd
	state         byte
	file          *bxFile
	LastBlockFlag byte
	BlockNum      uint16 //包号，如果是单包发送，则默认为 0x00。
	BlockLen      uint16 //包长，若是单包发送，此处为文件长度。
	BlockAddr     uint32 //本包数据在文件中的起始位置，如果是单包发送，此处默认为 0。
	temp          []byte
}

func (cmd *CmdWriteFile) Build() []byte {
	if cmd.state == 0 {
		//先计算区域数据及长度
		w0 := bytes.NewBuffer(make([]byte, 0, 1024))
		for _, v := range cmd.file.Areas {
			b := v.Build()
			binary.Write(w0, binary.LittleEndian, uint32(len(b))+4)
			binary.Write(w0, binary.LittleEndian, b)
		}
		l := w0.Len() + 27
		cmd.BlockLen = uint16(l)
		cmd.file.len = uint32(l)
		fmt.Println("传输的长度:", l)
		//Write File
		w1 := bytes.NewBuffer(make([]byte, 0, 1024))
		//文件描述数据
		binary.Write(w1, binary.LittleEndian, cmd.Group())
		binary.Write(w1, binary.LittleEndian, cmd.Cmd())
		binary.Write(w1, binary.LittleEndian, byte(0x01))
		binary.Write(w1, binary.LittleEndian, []byte{0x00, 0x00})
		binary.Write(w1, binary.BigEndian, []byte(cmd.file.name))
		binary.Write(w1, binary.LittleEndian, cmd.LastBlockFlag) //是否是最后一包,0x00——不是最后一包 0x01——最后一包。
		binary.Write(w1, binary.LittleEndian, cmd.BlockNum)      //包号,单包为0x00
		binary.Write(w1, binary.LittleEndian, cmd.BlockLen)      //包长，若是单包发送，此处为文件长度。
		binary.Write(w1, binary.LittleEndian, cmd.BlockAddr)     //本包数据在文件中的偏移量,单包为0x00
		//文件内容数据
		w2 := bytes.NewBuffer(make([]byte, 0, 1024))
		binary.Write(w2, binary.LittleEndian, cmd.file.type_)
		binary.Write(w2, binary.BigEndian, []byte(cmd.file.name))
		binary.Write(w2, binary.LittleEndian, cmd.file.len)
		binary.Write(w2, binary.LittleEndian, cmd.file.Priority)
		binary.Write(w2, binary.LittleEndian, cmd.file.DisplayType)
		binary.Write(w2, binary.LittleEndian, cmd.file.PlayTimes)
		binary.Write(w2, binary.BigEndian, cmd.file.encodeProgramLife())
		binary.Write(w2, binary.LittleEndian, cmd.file.ProgramWeek)
		binary.Write(w2, binary.LittleEndian, cmd.file.ProgramTime)
		binary.Write(w2, binary.LittleEndian, cmd.file.PlayPeriodGrpNum)
		//binary.Write(w, binary.LittleEndian, cmd.file.PlayPeriodSetting0)
		binary.Write(w2, binary.LittleEndian, byte(len(cmd.file.Areas)))
		binary.Write(w2, binary.LittleEndian, w0.Bytes())
		b2 := w2.Bytes()
		binary.Write(w1, binary.BigEndian, b2)
		crc16 := CRC16(b2, 0, w2.Len())
		fmt.Printf("文件校验:% 02x\n", crc16)
		binary.Write(w1, binary.LittleEndian, crc16)
		cmd.temp = w1.Bytes()
		//Start Write File "开始写文件",写文件前先检查内存是否够用
		w3 := bytes.NewBuffer(make([]byte, 0, 64))
		binary.Write(w3, binary.LittleEndian, CMD_START_WRITE_FILE.group)
		binary.Write(w3, binary.LittleEndian, CMD_START_WRITE_FILE.code)
		binary.Write(w3, binary.LittleEndian, byte(0x01))
		binary.Write(w3, binary.LittleEndian, []byte{0x00, 0x00})
		binary.Write(w3, binary.LittleEndian, byte(0x01)) //同名是否覆盖,0不覆盖,1覆盖
		binary.Write(w3, binary.BigEndian, []byte(cmd.file.name))
		binary.Write(w3, binary.LittleEndian, cmd.file.len)
		cmd.state = 1
		return w3.Bytes()
	} else {
		return cmd.temp
	}
}

type cmdFileBeginWrite struct {
	baseBxCmd
}

func NewCmdFileBeginWrite() cmdFileBeginWrite {
	return cmdFileBeginWrite{
		baseBxCmd: newBaseCmd(CMD_START_WRITE_FILE.group, CMD_START_WRITE_FILE.code),
	}
}
