<?php
namespace Api\PhpUtils\Common;

use Api\PhpUtils\Common\BaseConvert;

class Docid
{
    /**
     * 校验docid，10位以上docid为自媒体系统post_id fake的docid,U开头
     *
     * @param string $str
     * @return bool
     */
    public static function validDocid($str)
    {
        $strlen = strlen($str);
        if ($strlen === 37 && substr($str, 0, 5) === 'news_') return true;

        if (0 === strpos($str, 'C-'))//商品的 global id 也是有效的 docid
        {
            return self::validGlobalid($str);
        }

        $pos = strpos($str, '_');
        if ($pos !== false)
        {
            $str = substr($str, $pos + 1);
            $strlen = $strlen - ($pos + 1);
        }

        $chklen = 2;
        $code = substr($str, -$chklen);
        $str = substr($str, 0, $strlen-$chklen);
        $strlen -= $chklen;

        $base = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';

        if ($strlen % 2 == 1)
        {
            $str = '0' . $str;
            $strlen += 1;
        }

        $sum = 0;
        $len = $strlen/2;

        for ($i=0; $i<$len; $i++)
        {
            $sum *= 137;
            $sum += ord($str[$i]) ^ ord($str[$strlen-$i-1]);
        }

        $ret = '';

        for ($i=$chklen; $i>0; $i--)
        {
            $idx = $sum % 62;
            $sum = ($sum-$idx) / 62;
            $ret = $base[$idx] . $ret;
        }

        return $ret === $code;
    }

    /**
     * docid生成器, [不能用于全局], 仅为了兼容某些文章在未过审时, 没有全局docid, 而客户端又需要文章有docid的情况.
     * 用该生成器生成的docid能通过上述validDocid方法的检测
     *
     * @param int $id
     * @param string 生成的docid前缀
     * @return string
     */
    public static function generateDocid($id, $prefix)
    {
        $tmp = BaseConvert::decToOther($id);
        $len = strlen($tmp);
        $len = $len<6?6:$len;
        if ($len % 2 == 1)
        {
            $tmp = '0' . $tmp;
            $len += 1;
        }
        $tmp = str_pad(strval($tmp), $len<6?6:$len, '0', STR_PAD_LEFT);
        $sum = 0;
        for ($i = 0; $i < $len/2; $i++)
        {
            $sum *= 137;
            $sum += ord($tmp[$i]) ^ ord($tmp[$len - $i - 1]);
        }
        $code = '';
        $base = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
        for ($i = 2; $i > 0; $i--)
        {
            $idx = $sum % 62;
            $sum = ($sum - $idx) / 62;
            $code = $base[$idx] . $code;
        }

        return $prefix . $tmp . $code;
    }

    private static function generateGlobalidCheckString($global_id)
    {
        $md5_string = md5($global_id);
        $crc_32_string = strval(crc32($md5_string));
        $pos_array = array("0" => intval(substr($crc_32_string, 1, 1)), "1" => intval(substr($crc_32_string, 3, 1)), "2" => intval(substr($crc_32_string, 5, 1)));
        $check_string = substr($md5_string, $pos_array[0], 1) . substr($md5_string, $pos_array[1], 1) . substr($md5_string, $pos_array[2], 1);
        return $check_string;
    }

    private static function validGlobalid($global_id)
    {
        $str_len = strlen($global_id);
        $true_globalid = substr($global_id, 0, ($str_len - 3));
        $check_string = self::generateGlobalidCheckString($true_globalid);
        if ($check_string !== substr($global_id, -3))
        {
            return false;
        }
        return true;
    }
}
