<?php

// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2010 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: luofei614 <www.3g4k.com>
// +----------------------------------------------------------------------
// $Id: SaeStorage.class.php 2803 2012-03-06 14:57:17Z luofei614@gmail.com $
/**
 * storage模拟器
 * 在本地环境时，domain对应了Public文件夹下以domain名命名的的文件夹
 */
//本地默认的域在public中， 建立的文件夹名为域名。
class SaeStorage extends SaeObject {

    private $domainDir; //域的根目录
    private $filterPath;
    private $url;
    private $domainSize = array(); //记录域大小
    private $domainSizeFlag = "";

    //todu 增加api文档没有的函数
    public function __construct($_accessKey='', $_secretKey='') {
        global $sae_config;
        $this->domainDir = $sae_config['storage_dir'];
        $this->url = $sae_config['storage_url'];
        parent::__construct();
    }

    public function delete($domain, $filename) {
        $domain = trim($domain);
        $filename = $this->formatFilename($filename);
        if (Empty($domain) || Empty($filename)) {
            $this->errMsg = Imit_L("_SAE_STORAGE_PARAM_EMPTY_") . '[the value of parameter (domain,filename) can not be empty!]';
            $this->errNum = -101;
            return false;
        }
        $filepath = $this->domainDir . $domain . "/" . $filename;
        if (unlink($filepath)) {
            return true;
        } else {
            $this->errno = -1;
            $this->errmsg = Imit_L("_SAE_STORAGE_DELETE_ERR_");
            return false;
        }
    }

    public function deleteFolder($domain, $path) {
        $domain = trim($domain);
        $path = $this->formatFilename($path);
        if (Empty($domain) || Empty($path)) {
            $this->errmsg = Imit_L("_SAE_STORAGE_PARAM_EMPTY_") . '[the value of parameter (domain,path) can not be empty!]';
            $this->errno = -101;
            return false;
        }
        $folder = $this->domainDir . $domain . "/" . $path;
        $this->delDir($folder);
        return true;
    }

    private function delDir($directory) {
        if (is_dir($directory) == false) {
            exit("The Directory Is Not Exist!");
        }
        $handle = opendir($directory);
        while (($file = readdir($handle)) !== false) {
            if ($file != "." && $file != "..") {
                is_dir("$directory/$file") ?
                                $this->delDir("$directory/$file") :
                                unlink("$directory/$file");
            }
        }
        if (readdir($handle) == false) {
            closedir($handle);
            rmdir($directory);
        }
    }

    public function fileExists($domain, $filename) {
        $domain = trim($domain);
        $filename = $this->formatFilename($filename);
        if (Empty($domain) || Empty($filename)) {
            $this->errmsg = Imit_L("_SAE_STORAGE_PARAM_EMPTY_") . '[the value of parameter (domain,filename) can not be empty!]';
            $this->errno = -101;
            return false;
        }
        $filepath = $this->domainDir . $domain . "/" . $filename;
        return file_exists($filepath);
    }

    public function getAttr($domain, $filename, $attrKey=array()) {
        $filepath = $this->domainDir . $domain . "/" . $filename;
        if (!is_file($filepath)) {
            $this->errno = -1;
            $this->errmsg = Imit_L("_SAE_STORAGE_FILE_NOT_EXISTS_");
            return false;
        }
        if (empty($attrKey))
            $attrKey = array('fileName', 'length', 'datetime');
        $ret = array();
        foreach ($attrKey as $key) {
            switch ($key) {
                case "fileName":
                    $ret['fileName'] = $filename;
                    break;
                case "length":
                    $ret['length'] = filesize($filepath);
                    break;
                case "datetime":
                    $ret['datetime'] = filemtime($filepath); //todu 需要验证一下
                    break;
            }
        }
        return $ret;
    }

    public function getDomainCapacity($domain) {
        if (!isset($this->domainSize[$domain]))
            $this->getList($domain);
        return $this->domainSize[$domain];
    }

    public function getFilesNum($domain, $path=NULL) {
        static $filesNum = array();
        if (isset($filesNum[md5($domin . $path)]))
            return $filesNum[md5($domin . $path)];
        if ($path == NULL)
            $path = "*";
        $filesNum[md5($domin . $path)] = count($this->getList($domain, $path));
        return $filesNum[md5($domin . $path)];
    }

    public function getList($domain, $prefix='*', $limit=10, $offset=0) {
        $domain = trim($domain);
        if (Empty($domain)) {
            $this->errMsg = Imit_L("_SAE_STORAGE_PARAM_EMPTY_") . '[the value of parameter (domain) can not be empty!]';
            $this->errNum = -101;
            return false;
        }
        $path = $this->domainDir . $domain;
        $this->filterPath = $path . "/";
        //记录域的大小
        if ($prefix == "*" && !isset($this->domainSize[$domain]))
            $this->domainSizeFlag = $domain;
        $files = $this->getAllList($path, $prefix);
        $this->domainSizeFlag = "";
        //偏移
        return array_slice($files, $offset, $limit);
    }

    //获得所有文件
    private function getAllList($path, $prefix, &$files=array()) {
        $list = glob($path . "/" . $prefix);
        //循环处理，创建数组
        $dirs = array();
        $_files = array();
        foreach ($list as $i => $file) {
            if (is_dir($file) && !$this->isEmpty($file)) {//如果不是空文件夹
                $dirs[] = $file;
                continue;
            };
            if (!empty($this->domainSizeFlag))
                $this->domainSize[$this->domainSizeFlag]+=filesize($file); //统计大小


            $_files[$i]['name'] = str_replace($this->filterPath, '', $file); //不含域的名称
            $_files[$i]['isDir'] = is_dir($file);
        }
        //排序$_files
        $cmp_func = create_function('$a,$b', '
			$k="isDir";
			if($a[$k]  ==  $b[$k])  return  0;
			return  $a[$k]>$b[$k]?-1:1;
			');
        usort($_files, $cmp_func);
        foreach ($_files as $file) {
            //设置$files
            $files[] = $file['isDir'] ? $file['name'] . "/__________sae-dir-tag" : $file['name'];
        }
        //循环数组，读取二级目录
        foreach ($dirs as $dir) {
            $this->getAllList($dir, "*", $files);
        }
        return $files;
    }

    //判断是否为空目录
    private function isEmpty($directory) {
        $handle = opendir($directory);
        while (($file = readdir($handle)) !== false) {
            if ($file != "." && $file != "..") {
                closedir($handle);
                return false;
            }
        }
        closedir($handle);
        return true;
    }

    public function getListByPath($domain, $path=NULL, $limit=100, $offset=0, $fold=true) {
        $filepath = $this->domainDir . $domain . "/" . $path;
        $list = scandir($filepath);
        //读取非折叠数据
        $files = array();
        $dirnum = 0;
        $filenum = 0;
        foreach ($list as $file) {
            //统计
            if ($file == '.' || $file == '..')
                continue;
            $fullfile = $filepath . "/" . $file;
            if (is_dir($fullfile)) {
                $dirnum++;
                $filename = $fullfile . "/__________sae-dir-tag";
            } else {
                $filenum++;
                $filename = $fullfile;
            }

            $filename = str_replace($this->domainDir . $domain . "/", '', $filename);

            $files[] = array(
                'name' => basename($filename),
                'fullName' => $filename,
                'length' => filesize($fullfile),
                'uploadTime' => filectime($fullfile)
            );
        }
        //偏移
        $files = array_slice($files, $offset, $limit);
        if ($fold) {
            //折叠处理
            $rets = array(
                'dirNum' => $dirnum,
                'fileNum' => $filenum
            );
            foreach ($files as $file) {
                if ($file['name'] == "__________sae-dir-tag") {
                    //文件夹
                    $rets['dirs'][] = array(
                        'name' => $file['name'],
                        'fullName' => $file['fullName']
                    );
                } else {
                    $rets['files'][] = $file;
                }
            }
            return $rets;
        }
        return $files;
    }

    public function getUrl($domain, $filename) {
        $domain = trim($domain);
        $filename = $this->formatFilename($filename);
        return $this->url. $domain . "/" . $filename;
    }

    public function read($domain, $filename) {
        $domain = trim($domain);
        $filename = $this->formatFilename($filename);
        if (Empty($domain) || Empty($filename)) {
            $this->errmsg = Imit_L("_SAE_STORAGE_PARAM_EMPTY_") . '[the value of parameter (domain,filename) can not be empty!]';
            $this->errno = -101;
            return false;
        }
        $filepath = $this->domainDir . $domain . "/" . $filename;
        return file_get_contents($filepath);
    }

    public function setDomainAttr($domain, $attr=array()) {
        //pass
        return true;
    }

    public function setFileAttr($domain, $filename, $attr=array()) {
        //pass
        return true;
    }

    public function upload($domain, $destFileName, $srcFileName, $attr=array()) {
        $domain = trim($domain);
        $destFileName = $this->formatFilename($destFileName);
        if (Empty($domain) || Empty($destFileName) || Empty($srcFileName)) {
            $this->errmsg = Imit_L("_SAE_STORAGE_PARAM_EMPTY_") . '[the value of parameter (domain,destFile,srcFileName) can not be empty!]';
            $this->errno = -101;
            return false;
        }
		return $this->write($domain,$destFileName,file_get_contents($srcFileName));
    }

    public function write($domain, $destFileName, $content, $size=-1, $attr=array(), $compress=false) {
        if (Empty($domain) || Empty($destFileName)) {
            $this->errmsg = Imit_L("_SAE_STORAGE_PARAM_EMPTY_") . "[the value of parameter (domain,destFileName,content) can not be empty!]";
            $this->errno = -101;
            return false;
        }
        //定义文件路径
        $filepath = $this->domainDir . $domain . "/" . $destFileName;
        $this->mkdir(dirname($filepath));
        //设置长度
        if ($size > -1)
            $content = substr($content, 0, $size);
        //写入文件
        if (file_put_contents($filepath, $content)) {
            return true;
        } else {
            $this->errmsg = Imit_L('_SAE_STORAGE_SERVER_ERR_');
            $this->errno = -12;
            return false;
        }
    }

    //创建目录，无限层次。传递一个文件的
    private function mkdir($dir) {
        static $_dir; // 记录需要建立的目录
        if (!is_dir($dir)) {
            if (empty($_dir))
                $_dir = $dir;
            if (!is_dir(dirname($dir))) {
                $this->mkdir(dirname($dir));
            } else {
                mkdir($dir);
                if (!is_dir($_dir)) {
                    $this->mkdir($_dir);
                } else {
                    $_dir = "";
                }
            }
        }
    }

    private function formatFilename($filename) {
        $filename = trim($filename);

        $encodings = array('UTF-8', 'GBK', 'BIG5');

        $charset = mb_detect_encoding($filename, $encodings);
        if ($charset != 'UTF-8') {
            $filename = mb_convert_encoding($filename, "UTF-8", $charset);
        }

        return $filename;
    }

}

?>