<?php
namespace lib\excel;
/**
 * excelXlsx
 * https://github.com/viest/php-ext-xlswriter 需要1.5版本以上
 * https://xlswriter-docs.viest.me/zh-cn/kuai-su-shang-shou/chuang-jian-wen-jian
 * @author HzqGhost admin@whiledo.com QQ:313143468
 * @version 1.0.0
 *

	public function excel()
	{
        $data=[
            [
                'type'=>'image',
                'filename'=>'e:/1.jpg',
                'widthScale'=> 0.05,
                'heightScale'=> 0.05,
                'rowHeight'=> 190
            ],
            'b',
            'c'
         ];

        $excel = object(\lib\excel\excel::class,'xlsx');
        $excel->setConstMemory(true);
        $excel->setDirFile(DIR_CACHE.'/test.xlsx');
        $excel->header();
        $excel->bookBegin();
        $excel->sheetBegin('aaa');
        for($i=0;$i<10;$i++)
            $excel->append($data);
        $excel->sheetEnd();
        $excel->bookEnd();
	}

 */
class excelXlsx extends excelBase implements excelInterface
{
    protected $sheets = [];
    protected $rowI;
    protected $excel;
    protected $xlsfile;
    protected $fileHandle;
    protected $headerStyle;
    protected $wrapStyle;
    protected $maxColLabel = 'A';
    protected $hasHeader = false;
	public function __construct()
    {
        ;
    }

	public function bookBegin():excelInterface
    {
        if(empty($this->dirname)){
            trigger_error( slg('未定义excel输出目录,请先使用 $excel->setDir($dirname)'), E_USER_ERROR);
        }
        if(empty($this->filename)){
            trigger_error( slg('未定义excel输出文件,请先使用 $excel->setFile($filename)'), E_USER_ERROR);
        }
        $this->rowI = 0;
        $this->excel  = new \Vtiful\Kernel\Excel(['path' => $this->dirname]);
        return $this;
    }
	public function bookEnd()
    {
        $this->xlsfile->output();
        $this->excel->close();
        if($this->isOutput){
            $filename = $this->dirname.'/'.$this->filename;
            header('Content-Length: '.filesize($filename));
            readfile($filename);
            ob_end_flush();
            @unlink($filename);
            exit();
        }
    }
    
    public function formatHeaderRow(array $HeaderFields){
        $data = [];
        foreach($HeaderFields as $k=>$v){
            $data[$k] = $v[0];
        }
        return $data;
    }
    public function formatColumnStyle(array $HeaderFields){
        $data = [];
        foreach($HeaderFields as $k=>$v){
            $data[$k] = $v[1];
        }
        return $data;
    }

	public function sheetBegin(string $sheetName,array $headerRow=[],array $columnStyle=[]):excelInterface
    {
        $sheetName = str_replace(['/','\\',':','?','*','[',']','"',"'"],' ',$sheetName);
        $sheetName = substr($sheetName,0,30);
        $this->rowI = 0;
        $this->maxColLabel = 'A';
        $this->hasHeader = false;
        if(empty($this->sheets)){
            $this->sheets[] = $sheetName;
            if($this->isConstMemory){
                $this->xlsfile = $this->excel->constMemory($this->filename,$sheetName,false); // bool $enableZip64 需要1.5版本以上
            }else{
                $this->xlsfile = $this->excel->fileName($this->filename, $sheetName);
            }
            $this->fileHandle = $this->xlsfile->getHandle();
            $format = new \Vtiful\Kernel\Format($this->fileHandle);
            //头样式
            $this->headerStyle = $format->bold()
                        ->background(0x002F5F)
                        ->fontColor(0xFFFFFF)
                        ->toResource();
            //自动换行样式           
            $format = new \Vtiful\Kernel\Format($this->fileHandle);
            $this->wrapStyle = $format
                ->align(\Vtiful\Kernel\Format::FORMAT_ALIGN_VERTICAL_CENTER)
                ->wrap()
                ->toResource(); 
            //垂直居中对齐
            $format = new \Vtiful\Kernel\Format($this->fileHandle);
            $this->vCenterStyle = $format
                ->align(\Vtiful\Kernel\Format::FORMAT_ALIGN_VERTICAL_CENTER)
                ->toResource();            
        }else{
            $this->sheets[] = $sheetName;
            $this->excel->addSheet($sheetName);
        }
        if($headerRow){
            $this->hasHeader = true;
            $this->excel->checkoutSheet($this->sheets[count($this->sheets)-1]);
            $this->excel->autoFilter('A0:'.$this->int2Excel(count($headerRow)-1).'0');
            $this->xlsfile->setRow('A1', 16, $this->headerStyle); // 写入数据前设置行样式(范围,高度,样式)
            $colI=0;
            $data=[];
            foreach($headerRow as $k=>$cell){
                if($columnStyle && array_key_exists($k,$columnStyle)){
                    $width = $columnStyle[$k]['width'];
                    $wrap = $columnStyle[$k]['wrap'] ?? false;
                    if($wrap){
                        $this->xlsfile->setColumn($this->int2Excel($colI).':'.$this->int2Excel($colI), $width, $this->wrapStyle);
                    }else{
                        $this->xlsfile->setColumn($this->int2Excel($colI).':'.$this->int2Excel($colI), $width, $this->vCenterStyle);
                    }
                }else{
                    $this->xlsfile->setColumn($this->int2Excel($colI).':'.$this->int2Excel($colI), 20, $this->vCenterStyle);
                }
                $data[] = $cell;
                $colI++;
            }
            $this->xlsfile->header($data);
            $this->rowI++;
        }
        return $this;
    }

	public function sheetEnd():excelInterface
    {
        return $this;
    }

	public function append(array $row=[]):excelInterface
    {
        if($row){
            $colI=0;
            foreach($row as $k=>$cell){
                if(!is_array($cell)){
                    $cell  = substr($cell,0,32000); //32767
                    $this->xlsfile->insertText($this->rowI, $colI, $cell);
                }else{
                    if($cell['type']=='image'){
                        if($cell['filename']){
                            $this->xlsfile->insertImage($this->rowI, $colI, $cell['filename'],$cell['widthScale'],$cell['heightScale']);
                        }
                        $this->xlsfile->setRow('A'.($this->rowI+1).':'.'A'.($this->rowI+1),$cell['rowHeight'],$this->vCenterStyle);
                    }
                }
                $colI++;
            }
            if($this->maxColLabel=='A'){
                $this->maxColLabel = $this->int2Excel($colI);
            }
            $this->rowI++;
        }
        return $this;
    }   

    /** 回调读取 
    * @param function $callback 回调函数原型 function ($row, $col, $data)
    * @remark 每行末尾，将会附加一次回调，并传递 XLSX_ROW_END 为当前行结束标识。
    */
	public function each($callback,$sheetName=null)
	{
        $excel  = new \Vtiful\Kernel\Excel(['path' => $this->dirname]);
        $excel->openFile($this->filename)->nextCellCallback($callback,$sheetName);
        $excel->close();
	}

	public function toArray($types=[]):array
	{
        $excel  = new \Vtiful\Kernel\Excel(['path' => $this->dirname]);
        $res = $excel->openFile($this->filename)->openSheet();
        if( $res == false ){
            trigger_error( slg('打开excel文件出错').' '.$this->dirname.'/'.$this->filename, E_USER_ERROR);
        }
        $header = $excel->nextRow();
        $cellTypes = [];
        foreach($header as $k=>$v){
            if(isset($types[$k])){
                $cellTypes[] = $types[$k];
            }else{
                $cellTypes[] = \Vtiful\Kernel\Excel::TYPE_STRING;
            }
        }
        $excel->setType($cellTypes);
        $data = $excel->getSheetData();
        $excel->close();
        array_unshift($data,$header);
        return $data ?? [];
	}
    
    public function toCsv($dist):bool{
        parent::toCsv($dist);
        if(is_string($dist)){
            $fp = fopen($dist,'w');
        }elseif(is_resource($dist)){
            $fp = $dist;
        }else{
            trigger_error( slg('请传递一个文件流或者文件路径'), E_USER_ERROR);
        }
        $excel  = new \Vtiful\Kernel\Excel(['path' => $this->dirname]);
        $res = $excel->openFile($this->filename)->openSheet()->putCSV($fp);
        $excel->close();
        if(is_string($dist)){
            fclose($fp);
        }
        if( $res == false ){
            trigger_error( slg('打开excel文件出错').' '.$this->dirname.'/'.$this->filename, E_USER_ERROR);
        }
        return true;
    }
}