<?php
namespace imcat;

// DBExt
class glbDBExt{    
    
    static function moveOneField($mod, $cid){
        $db = glbDBObj::dbObj();
        // create:field
        $tabf = 'base_fields';
        $r = $db->table($tabf)->where("model='$mod' AND kid='$cid'")->find();
        if(in_array($r['dbtype'],array('nodb','file'))) return; 
        $tabid = (empty($r['etab'])?'docs':'dext')."_$mod"; 
        $tabto = (empty($r['etab'])?'dext':'docs')."_$mod"; 
        $cols = $db->fields($tabto); 
        self::setOneFAE($tabto,$cid,$r,$cols);
        // move:data
        $sin = "SELECT `$cid` FROM $db->pre{$tabid}$db->ext f WHERE f.did=n.did";
        $sql = "UPDATE $db->pre{$tabto}$db->ext n SET n.$cid = ($sin) "; 
        $db->query($sql);
        // end:del-old-field, upd-field-cfg
        $db->query("ALTER TABLE $db->pre{$tabid}$db->ext DROP `$cid` ");
        $dupd['etab'] = empty($r['etab']) ? '1' : '0';
        $db->table($tabf)->data($dupd)->where("model='$mod' AND kid='$cid'")->update();
        glbCUpd::upd_model($mod);
    }

    // 字段 - 添加/删除/修改 
    static function setOneField($mod,$cid,$act='del',$cfg=array()){
        $db = glbDBObj::dbObj();
        $tabf = 'base_fields';
        $r = $db->table($tabf)->where("model='$mod' AND kid='$cid'")->find();
        if(!empty($r) && in_array($r['dbtype'],array('nodb','file'))) return; # $r null
        if(empty($r) && !empty($cfg)) $r = $cfg;
        $tabid = self::getTable($mod,empty($r['etab'])?'0':1); 
        $cols = $db->fields($tabid); 
        if($act=='del'){
            if(isset($cols[$cid])) $db->query("ALTER TABLE $db->pre{$tabid}$db->ext DROP `$cid` ");
            $db->table($tabf)->where("model='$mod' AND kid='$cid'")->delete();     
        }else{
            self::setOneFAE($tabid,$cid,$r,$cols);
        }
    }
    static function setOneFAE($tabid,$cid,$r,$cols=array()){
        $db = glbDBObj::dbObj();
        $sql = "ALTER TABLE $db->pre{$tabid}$db->ext";
        if(isset($cols[$cid])) $sql.= " CHANGE `$cid` ";
        else                   $sql.= " ADD ";
        $dblen = intval(@$r['dblen']);
        $sql.= " `$cid` $r[dbtype]".($r['dbtype']=='varchar' ? ($dblen>0?"($dblen)":'(12)') : ''); 
        $sql.= (strpos("($r[vreg]",'nul:') ? " NULL " : ' NOT NULL '); 
        if(strstr($r['dbtype'],'char')){
            $sql.= " DEFAULT '".(strlen($r['dbdef'])==0?'':$r['dbdef'])."' "; 
        }elseif(strstr($r['dbtype'],'int') || in_array($r['dbtype'],['float','double','decimal'])){
            $sql.= " DEFAULT '".(strlen($r['dbdef'])==0?'0':$r['dbdef'])."' "; 
        }
        $after = self::findAfterField($cols,$cid);
        if(!isset($cols[$cid])) $after && $sql.= " AFTER `$after` ";
        $db->query($sql);
    }

    static function setfieldDemo($mod,$obj,$org='(drop)'){
        $db = glbDBObj::dbObj();
        if($org=='(drop)'){
            $db->query("DROP TABLE IF EXISTS $db->pre{$obj}$db->ext ");
            $db->table('base_fields')->where("model='$mod'")->delete(); 
        }else{ 
            $_ta = explode('_',$org);
            $obj && $db->query("CREATE TABLE IF NOT EXISTS $db->pre{$obj}$db->ext LIKE $db->pre{$org}$db->ext");
            if(in_array($_ta[0],array('coms','docs','users'))){ //增加默认字段配置'dext',
                $pid = $_ta[1]; 
                $_cfg = glbConfig::read($pid);
                $farr = @$_cfg['f']; 
                $top = 120; 
                if($farr){ foreach($farr as $k=>$v){
                    $tabid = 'base_fields';
                    if(!$db->table($tabid)->where("kid='$k' AND model='$mod'")->find()){
                        $fm = array('kid'=>$k,'model'=>$mod,'top'=>$top,)+$v; 
                        $db->table($tabid)->data($fm)->insert();
                    }
                    $top += 4; 
                } }
            }
        }
    }
    
    // tab下-添加字段，在什么字段后面
    static function findAfterField($tab,$col){
        $_groups = glbConfig::read('groups');
        $a = is_array($tab) ? $tab : $db->fields($tab);
        if(isset($_groups[$col]) && $_groups[$col]['pid']=='types' && isset($a['catid'])){
            $def = 'catid';
        }else{
            $def = ''; $bak = ''; 
            foreach($a as $k=>$v){
                if($k=='aip'){ 
                    $def = empty($bak) ? 'aip' : $bak;
                    break;
                }
                if(substr("$k)))",0,3)==substr("$col)))",0,3)){
                    $def = $k;
                }
                $bak = $k;
            }
        }
        return $def;
    }
        
    /* *****************************************************************************
      *** 数据库相关函数 
    - db前缀
    - by Peace(XieYS) 2012-07-23
    ***************************************************************************** */
    // tab, $tmp(md2,md3,mdh),max,
    static function dbAutID($tab='utest_keyid',$tmp='max',$n=0){
        $db = glbDBObj::dbObj();
        $tabf = $db->pre.$tab.$db->ext;
        $tfix = substr($tab,0,5); 
        if(in_array($tfix,array('docs_','coms_','advs_','users'))){
            $tkey = substr($tfix,0,1).'id';
            $tno = substr($tfix,0,1).'no';
        }else{
            $tkey = 'kid'; 
            $tno = 'kno';
        }
        $ktmp = basKeyid::kidTemp($tmp); // 2018-mdh-1233
        if($tmp=='max'){
            $kno = 1;
            $kid = $ktmp;
        }else{
            $pdb = substr($ktmp,0,strrpos($ktmp,'-')).'%';
            $mdb = $db->query("SELECT max($tno) as $tno FROM $tabf WHERE $tkey LIKE '$pdb'");
            $kno = empty($mdb[0][$tno]) ? 1 : ($mdb[0][$tno]+1) % 99;
            $kfix = $kno<10 ? '0'.$kno : $kno;
            $kid = substr($ktmp,0,strlen($ktmp)-2).$kfix;
        }
        if($n) $kid = substr($kid,0,strlen($kid)-2).basKeyid::kidRand('k',2);
        $rec = $db->table($tab)->where("$tkey='$kid%'")->find();
        if($rec) return self::dbAutID($tab,$tmp,$n+1);
        else return array($kid,$kno);
    }

    static function dbNxtID($tab,$mod,$pid='0'){
        $sqlm = $tab=='bext_relat' ? '' : ($tab=='base_model' ? 'pid' : 'model')."='$mod' AND ";
        $mcfg = glbConfig::read($mod); //"$sqlm kid REGEXP ('^{$fix}[0-9]{3}$')";
        $fd = $pid ? ($mcfg['i'][$pid]['deep']+1) : '1';
        $tid = ''; // 找:本pid下最大的一个ID
        if(!empty($mcfg['i'])){ foreach($mcfg['i'] as $ik=>$iv) {
            if($iv['pid']==$pid && preg_match("/^[a-z]{1,6}\d{2,10}$/i",$ik)){
                $tid = max($tid,$ik);
            }
        } }
        if($tid){ // 找:所有的类似最大的一个ID
            preg_match("/^([a-z]{1,5})(\d{2,10})$/i",$tid,$tmp); 
            $fix = $tmp[1]; $no = $tmp[2]; $nl = strlen($no);
            foreach($mcfg['i'] as $ik=>$iv) {
                if($iv['pid']==$pid) continue;
                if($iv['deep']!=$fd) continue;
                if(preg_match("/^$fix\d{{$nl}}$/i",$ik)){
                    $tid = max($tid,$ik);
                }
            } //echo $tid;
            // 找:下一个
            preg_match("/^([a-z]{1,5})(\d{2,10})$/i",$tid,$tmp);
            $nid = $fix.basKeyid::kidNext('',$tmp[2],$tmp[2],2,strlen($tmp[2]));
            // 是否存在
            $whr = "$sqlm kid='$nid'"; // echo "(n=$nid";
            $re = glbDBObj::dbObj()->table($tab)->where($whr)->order('kid DESC')->find();
            if(!$re){ return $nid; }
        }
        $fix = substr($mod,0,1).$fd;
        $whr = "$sqlm kid LIKE '$fix%'";
        $re = glbDBObj::dbObj()->table($tab)->where($whr)->order('kid DESC')->find();
        if($re){
            $nid = substr($re['kid'],2);
            $nid = basKeyid::kidNext('',$nid,'012',2,3);
        }else{ $nid = '012'; }
        return $fix.$nid;
    }
    
    // ext: 0-tab, 1-ext, kid, arr
    static function getTable($mod,$ext='0'){ 
        $_groups = glbConfig::read('groups');
        if(!isset($_groups[$mod])) return '';
        if($_groups[$mod]['pid']=='docs'){
            $tabid = $ext==1 ? 'dext_'.$mod : 'docs_'.$mod;
            $keyid = 'did';
        }elseif($_groups[$mod]['pid']=='users'){
            $tabid = 'users_'.$mod;
            $keyid = 'uid';
        }elseif($_groups[$mod]['pid']=='advs'){
            $tabid = 'advs_'.$mod;
            $keyid = 'aid';
        }elseif($_groups[$mod]['pid']=='coms'){    
            $tabid = 'coms_'.$mod;
            $keyid = 'cid';
        }elseif($_groups[$mod]['pid']=='types'){    
            $tabid = empty($_groups[$mod]['etab']) ? 'types_common' : 'types_'.$mod;
            $keyid = 'kid';
        }else{
            $tabid = $keyid = '';    
        }
        if(is_numeric($ext)){ // 0, 1
            return $tabid;
        }else{ // kid,arr
            return $ext=='kid' ? $keyid : array($tabid,$keyid);
        }
    }
    
    static function getKids($mod,$kid='',$whr='',$ret='sub'){
        $tabid = self::getTable($mod); 
        $kid = $kid ? basStr::filKey($kid,'_-.') : self::getKeyid($mod); 
        $list = glbDBObj::dbObj()->table($tabid)->field($kid)->where($whr)->select();
        $re = array();
        if($list){
        foreach($list as $r){
            $re[] = $r[$kid];
        } }
        if(empty($re)){
            $re[] = '(null)';    
        }
        if($ret=='sub'){
            $re = "'".implode("','",$re)."'";
        }
        return $re;
    }
    
    static function dbComment($tabid='~return~'){ 
        static $dbdict,$fmod,$fdemo;
        $db = glbDBObj::dbObj();
        $fsystem = basLang::ucfg('fsystem');
        if(empty($dbdict)){
            $dict = $db->table('bext_dbdict')->field("kid,tabid,title")->select();
            foreach($dict as $v){
                $dbdict[$v['tabid']][$v['kid']] = $v['title'];
            }
        }
        if(empty($fmod)){
            $dict = $db->table('base_fields')->field("kid,model,title")->select();
            foreach($dict as $v){
                $fmod[$v['model']][$v['kid']] = $v['title'];
            }
        }    
        if(empty($fdemo)){
            $fdemo = array();
            $demo = glbConfig::read('fdemo','sy');
            foreach(array('init_users','init_coms','init_dext','init_docs',) as $part){
                $fpart = $demo[$part];
                foreach($fpart as $f=>$v){
                    $fdemo[$f] = $v['title'];
            } }
        }
        if($tabid=='~return~') return array('fsystem'=>$fsystem,'fdemo'=>$fdemo,);
        $fields = $db->fields($tabid);
        $moda = explode('_',$tabid); 
        $modid = $moda[1];
        foreach($fields as $f=>$v){
            $flag = 'def'; $rem = '';
            if(isset($fmod[$modid][$f])){ //模型设置
                $flag = 'mod';
                $rem = $fmod[$modid][$f];
            }elseif(empty($dbdict[$tabid][$f])){ //dbdict为空
                if(isset($fdemo[$f])){
                    $flag = 'demo';
                    $rem = $fdemo[$f];
                }
                if(isset($fsystem[$f])){
                    $flag = 'sys';
                    $rem = $fsystem[$f];
                }
            }else{ //dbdict设置
                $rem = $dbdict[$tabid][$f];    
                if(isset($fsystem[$f]) || in_array($moda[0],array('active','advs','base','bext','logs'))){
                    $flag = 'sys';
                }
            }
            $fields[$f]['_flag'] = $flag;
            $fields[$f]['_rem'] = basStr::filTitle($rem);
        }
        $_groups = glbConfig::read('groups');
        if(isset($_groups[$modid]) && $_groups[$modid]['pid']==$moda[0]){
            $fields[0]['_flag'] = 'sys'; 
            $cfg = basLang::ucfg('cfglibs.dbext');
            $fields[0]['_rem'] = $_groups[$modid]['title'].('['.$cfg[$moda[0]].']').basLang::show('dbdict_tab');
        }
        if(isset($_groups[$modid]) && $moda[0]=='dext'){
            $fields[0]['_flag'] = 'sys';
            $fields[0]['_rem'] = $_groups[$modid]['title'].basLang::show('dbdict_extab');
        }
        if(isset($fsystem['_stabs'][$tabid])){
            $fields[0]['_flag'] = 'sys';
            $fields[0]['_rem'] = $fsystem['_stabs'][$tabid];
        }
        if(empty($fields[0]['_rem'])&& !empty($dbdict[$tabid][0])){
            $fields[0]['_flag'] = '';
            $fields[0]['_rem'] = $dbdict[$tabid][0];
        }
        return $fields;
    }
    
    // 获取一组扩展参数
    static function getExtp($type){ 
        $data = array();
        $whr = strpos($type,'%') ? " LIKE '$type'" : "='$type'";
        $list = glbDBObj::dbObj()->table('bext_paras')->where("pid$whr AND enable=1")->order('top')->limit(99)->select();
        if($list){ foreach($list as $i=>$r){ 
            $r['i'] = $i+1;
            foreach(array('aip','atime','auser','eip','etime','euser','cfgs','note','enable') as $k2){
                unset($r[$k2]);
            }
            $data[$r['kid']] = $r;
        } } 
        return $data;
    }

}
