/*
NAME: 
DESCRIPTION: ;
PARAMETER:
	[
		{
			name : 'step',
			title : '过滤Step',
			type : 'LineEdit',
			property : {tool_tip : '过滤Step'},
		},
		{
            name : 'auto_save',
			title : '自动保存',
            type : 'RadioBox',
            property : {
				item_list:[
					{name:'yes',text:'YES'},
					{name:'no',text:'NO'},
				],
				tool_tip:'是否自动保存料号开关'
			}
        }
	]
 VERSION_HISTORY:
	V1.00 2020-09-25 Scott Sun
	    1.新版本
		
 HELP:
    <html><body bgcolor="#DDECFE">
		<font size="3" color="#003DB2"><p>功能简介</p></font>
		<p> sec drc 分析 </p>
		<br>
		<font size="3" color="#003DB2"><p>参数配置</p></font>
		<p> step信息 </p>
		<br>
		<font size="3" color="#003DB2"><p>注意事项</p></font>
		<p> 无 </p>
		<br>
	</body></html>	
*/


// 引入模块 包
var $ = require('topcam.scriptfunc').argv();
var fs = require('fs');
var _ = require('lodash');
var mode = $.ikm ? "topcam" : "aimdfm";
var IKM = $.ikm; 
if (IKM==undefined ) { IKM = require('topcam.ikm6')($) }
var GEN = $.gen;
var GUI = $.gui || {};
var Job = $.job || $.job_name;
var JobId = $.job_id;
var db = $.db || IKM.db
var PAR = {}
if ($.par) { PAR = $.par } else if ($.hasOwnProperty('script_parameter')){ PAR = JSON.parse($.script_parameter); }
if (mode === "aimdfm") {
	var database = require("topsin.database");
	database.addConnection($.conf.database_conf, "DFM");
	var QDfm = database.query("DFM");
	$.QDfm = QDfm;
	if ($.conf.product_type == "aimdfm") {
		QDfm.updateRow({ table: "pdm_aimdfm_task", data: { current_process_title: $.process_title }, where: { id: $.task_id } });
	}
}
var Status = 'ok';
var resultData = [];
var par = PAR;
var default_par = {
    step: "drc",
    auto_save: "No",
    units: "mm"
}
for(var key in default_par){ if (!par.hasOwnProperty(key) || par[key] == ""){ par[key] = default_par[key] }}
var job = Job;
var Omatrix;
try {
	if(_.isEmpty(job)){throw "参数job不存在"} else { job = job.toLowerCase() }
	if(!GEN.isJobExists({job:job})){throw "料号"+job+"不存在"}
	if(!GEN.isJobOpen({job:job})){ GEN.openJob({job:job}) }
    if(mode == "aimdfm"){ if(GEN.checkInout({job:job,mode:"test"}) != 0){ throw "the job check" } else { GEN.checkInout({job:job,mode:"out"}) } }

    var stepList = GEN.getStepList({job:job})
	stepList = stepList.filter(function(v){
		var reg = new RegExp(par.step,"ig")
		return reg.test(v)
	})
	if(stepList.length == 0){throw "未找到step"}

    // 上传matrix信息
    var matrix = UPLOAD_LAYER_MATRIX({job:job})  // 分析matrix 获得分析后的matrix信息

    var board_thickness = IKM.get_jobinfo({jobid:JobId,jobinfo:"board_thickness"}) || 0;
    board_thickness *= 1000 ;
    stepList.forEach(function (step) {
        GEN.openStep({job:job,name:step});
        GEN.clearLayers();
        GEN.affectedLayer( {mode:'all',affected:'no'} );
        GEN.COM( "sel_options,clear_mode=clear_after,display_mode=all_layers,area_inout=inside,area_select=select,select_mode=standard,area_touching_mode=exclude");
        GEN.units( {type:par.units} );
        GEN.zoomHome();

        var check_list = 'pcb_analysis_jt01';
        var signal = "", signals = [];
        var pg_layer = "", pg_layers = [];
        var drill = [];
        var sm_layers = [] , ss_layer = "", ss_layers = [];
	    // var ($signal,@signal,@pg_layer,$pg_layer,@drill,@sm_layer,@ss_layer,$ss_layer);
        var matrix = GEN.getMatrix({job:job});
        for (var layer in matrix) {
            var layerInfo = matrix[layer];
            if(layerInfo.context == "board") {
                if(layerInfo.layer_type == 'signal' && /(cil)|(col)/.test(layer)){
                    var lyr_paras = {};
                    if(layerInfo.side == 'top'){
                        lyr_paras.layer1 = layer;
                        lyr_paras.drills = 'yes';
                        lyr_paras.thickness = board_thickness/2;
                    }else if(layerInfo.side == 'bottom'){
                        lyr_paras.layer2 = layer;
                        lyr_paras.drills = 'yes';
                        lyr_paras.thickness = board_thickness/2;
                    }else{
                        lyr_paras.layer1 = layer;
                        lyr_paras.drills = 'no';
                        lyr_paras.thickness = 0;
                    }
                    var copperArea = GEN.copperArea(lyr_paras);
                    copperArea.area = Number(copperArea.area).toFixed(3) - 0;
                    copperArea.percent = parseInt(copperArea.percent)
                    IKM.save_layerinfo({jobid:JobId,
                                        jobcategory:'org',
                                        tlname:layerInfo.tl_name,
                                        layerinfohash:{copper_area_pcs:copperArea.area,
                                                        copper_area_ratio_pcs:copperArea.percent}
                                        });
                    signals.push(layer)
                    layer += ';';
                    signal += layer; 
                }else if(layerInfo.layer_type == 'power_ground' && /(cil)/.test(layer)){
                    var lyr_paras = {
                        layer1 : layer,
                        drills : 'no',
                        thickness : 0
                    };
                    var copperArea = GEN.copperArea(lyr_paras);
                    copperArea.area = Number(copperArea.area).toFixed(3) - 0;
                    copperArea.percent = parseInt(copperArea.percent)
                    IKM.save_layerinfo({jobid:JobId,
                                        jobcategory:'org',
                                        tlname:layerInfo.tl_name,
                                        layerinfohash:{copper_area_pcs:copperArea.area,
                                                        copper_area_ratio_pcs:copperArea.percent}
                                        });
                    pg_layers.push(layer)
                    layer += ';';
                    pg_layer += layer; 
                } else if(layerInfo.layer_type == 'drill'){
                    drill.push(layer)
                } else if (layerInfo.layer_type == 'silk_screen' && /lpp/.test(layer)) {
                    var lyr_paras = {
                        layer1 : layer,
                        drills : 'no',
                        thickness : 0
                    };
                    var copperArea = GEN.copperArea(lyr_paras);
                    copperArea.area = Number(copperArea.area).toFixed(3) - 0;
                    copperArea.percent = parseInt(copperArea.percent)
                    var target_attrname = layerInfo.side == 'top' ? 'ss_area_pcs_top' : 'ss_area_pcs_bot';
                    var jobinfohash = {};
                    jobinfohash[target_attrname] = copperArea.area;
                    IKM.save_jobinfo({
                        jobid:JobId,
                        jobcategory:'work',
                        jobinfohash:jobinfohash
                    });
                    ss_layers.push(layer)
                    layer += ';';
                    ss_layer += layer;
                }else if(layerInfo.layer_type == 'solder_mask' && /smf/.test(layer)){
                    sm_layers.push(layer)
                }
            }
        }
            
        var tmp_layer = 'tl+copper+tmp++';
        GEN.createLayer({job:job,layer:'tl+copper+tmp++',context:'misc',type:'signal',delete_exists:'yes'});
        GEN.affectedLayer({affected:'yes',layer:tmp_layer,clear_before:'yes'});
        var profile_limits = GEN.getProfileLimits({job:job,step:step,units:par.units});
        
        if(profile_limits.xsize == 0){
            GEN.affectedLayer( {mode:'all',affected:'no'} );
            GEN.deleteLayer({job:job,layer:tmp_layer,step:step});
            throw 'Cancel';
        }else{
            GEN.srFill({layer:tmp_layer});
            var lyr_paras = {};
            lyr_paras.layer1 = tmp_layer;
            lyr_paras.drills = 'no';
            lyr_paras.thickness = 0;
            var copperArea = GEN.copperArea(lyr_paras);
            copperArea.area = Number(copperArea.area).toFixed(3) - 0;
            copperArea.percent = parseInt(copperArea.percent)
            GEN.affectedLayer( {mode:'all',affected:'no'} );
            GEN.deleteLayer({job:job,layer:tmp_layer,step:step});
            IKM.save_layerinfo({jobid:JobId,
                            jobcategory:'org',
                            tlname:step,
                            layerinfohash:{board_area_pcs:copperArea.area,
                                            board_area_ratio_pcs:copperArea.percent}
                        });
        }


        if(GEN.isChklistExists({job:job,step:step,chklist:check_list})){
            GEN.COM('chklist_delete',{chklist:check_list});
        }
    
        GEN.COM("chklist_from_lib,chklist=" + check_list);
        GEN.COM("chklist_open,chklist=" + check_list);
        GEN.COM("chklist_show,chklist=" + check_list);
    
        GEN.chklistSelectAct({job:job,step:step,chklist:check_list,nact:1,select:'yes',clear_before:'yes'});
        if(pg_layers.length > 0){
            GEN.COM('chklist_select_act',{chklist:check_list,nact:2,select:'yes'});//运行PG层分析
        }
        if(sm_layers.length > 0){
            GEN.COM('chklist_select_act',{chklist:check_list,nact:3,select:'yes'});
        }
        if(ss_layers.length > 0){
            GEN.COM('chklist_select_act',{chklist:check_list,nact:4,select:'yes'});
        }
        
        GEN.COM('chklist_select_act',{chklist:check_list,nact:5,select:'yes'});
    
        GEN.chklistCupd({chklist:check_list,nact:1,params:{pp_layer:signal,pp_d2c:500,pp_tests:'Spacing\;Drill\;Size\;Rout\;SMD'}});
    
        if(ss_layers.length > 0){
            GEN.chklistCupd({chklist:check_list,nact:4,params:{pp_layers:ss_layer}});
        }
        
        if(pg_layers.length > 0){
            GEN.chklistCupd({chklist:check_list,nact:2,params:{pp_layers:pg_layer,pp_tests:'Drill\;Rout'}});
        }
    
        GEN.chklistCupd({chklist:check_list,nact:5,params:{pp_tests:'Hole Separation\;NPTH to Rout'}});
    
        GEN.chklistRun({chklist:check_list,nact:'s'});

        // 分析取得结果插入数据库
        var dirll_info = {},signal_info={},sm_info={};
        for (var i in drill) {
            var drl = drill[i];
            var drill_meas  = GEN.getCheckMeas({job:job,step:step,chklist:check_list,nact:5,units:par.units,layer:drl});
            var same_net = drill_meas.filter(function(v){return /same/.test(v)})
            var diff_net = drill_meas.filter(function(v){return /diff/.test(v)})
            var drill_to_outline = drill_meas.filter(function(v){return /drill_to_outline/.test(v)})
            var np_to_rout = drill_meas.filter(function(v){return /npth2rout/.test(v)})
            dirll_info[drl] = {};
            if(same_net.length > 0){
                var tmp = same_net[0].split(/\s+/);
                dirll_info[drl]["same_min"] = (tmp[2]/1000).toFixed(3);
            }else{
                dirll_info[drl]["same_min"] = '/';
            }

            if(diff_net.length > 0){
                var tmp = diff_net[0].split(/\s+/);
                dirll_info[drl]["diff_min"] = (tmp[2]/1000).toFixed(3);
            }else{
                dirll_info[drl]["diff_min"] = '/';
            }
            
            if(drill_to_outline.length > 0){
                var tmp = drill_to_outline[0].split(/\s+/);
                dirll_info[drl]["drill_to_outline"] = (tmp[2]/1000).toFixed(3);
            }else{
                dirll_info[drl]["drill_to_outline"] = '/';
            }
            if(np_to_rout.length > 0){
                var tmp = np_to_rout[0].split(/\s+/);
                dirll_info[drl]["np_to_rout"] = (tmp[2]/1000).toFixed(3);
            }else{
                dirll_info[drl]["np_to_rout"] = '/';
            }
            IKM.save_layerinfo({jobid:JobId,
                                jobcategory:'org',
                                tlname:matrix[drl].tl_name,
                                layerinfohash:{h2h_min_same_layer:dirll_info[drl].same_min,
                                                h2h_min_different_layer:dirll_info[drl].diff_min,
                                                drill_to_rout:dirll_info[drl].drill_to_outline,
                                                npth_to_rout:dirll_info[drl].np_to_rout
                                                }
                                });
        }
        signals.forEach(function(layer){
            var signal_meas = GEN.getCheckMeas({job:job,step:step,chklist:check_list,nact:1,units:par.units,layer:layer});
            var line_to_line = signal_meas.filter(function(v){return /l2l/.test(v)})
            var line_to_pad = signal_meas.filter(function(v){return /p2line/.test(v)})  // 线到pad
            var pad_to_pad = signal_meas.filter(function(v){return /pth2pth|via2via/.test(v)})  // pad到pad
            var hole_to_copper = signal_meas.filter(function(v){return /(via2l)|(via2c)|(pth2c)|(pth2l)/.test(v)})  // hole到copper
            var min_ring = signal_meas.filter(function(v){return /(via_ar)|(pth_ar)/.test(v)})  // 最小ring
            var min_line = signal_meas.filter(function(v){return /(line)|(arc)/.test(v)})   // 最小线宽
            var smd_pitch = signal_meas.filter(function(v){return /smd_pitch/.test(v)}) // SMD_pith
            var bga_pitch = signal_meas.filter(function(v){return /bga_pitch/.test(v)}) // BGA_pith
            var rout_copper = signal_meas.filter(function(v){return /r2c/.test(v)}) // rout to copper
            if(!signal_info[layer]){signal_info[layer] = {}}
            if(line_to_line.length > 0){
                var tmp = line_to_line[0].split(/\s+/)
                signal_info[layer].line_to_line = (tmp[2]/1000).toFixed(3);
            }else{
                signal_info[layer].line_to_line = '/';
            }
    
            if(line_to_pad.length > 0){
                var tmp = line_to_pad[0].split(/\s+/)
                signal_info[layer].line_to_pad = (tmp[2]/1000).toFixed(3);
            }else{
                signal_info[layer].line_to_pad = '/';
            }
    
            if(pad_to_pad.length > 0){
                var tmp = pad_to_pad[0].split(/\s+/)
                signal_info[layer].pad_to_pad = (tmp[2]/1000).toFixed(3);
            }else{
                signal_info[layer].pad_to_pad = '/';
            }
    
            if(hole_to_copper.length > 0){
                var tmp = hole_to_copper[0].split(/\s+/)
                signal_info[layer].hole_to_copper = (tmp[2]/1000).toFixed(3);
            }else{
                signal_info[layer].hole_to_copper = '/';
            }
    
            if(min_ring.length > 0){
                var tmp = min_ring[0].split(/\s+/)
                signal_info[layer].min_ring = (tmp[2]/1000).toFixed(3);
            }else{
                signal_info[layer].min_ring = '/';
            }
    
            if(min_line.length > 0){
                var tmp = min_line[0].split(/\s+/)
                signal_info[layer].min_line = (tmp[2]/1000).toFixed(3);
            }else{
                signal_info[layer].min_line = '/';
            }
            
            if(smd_pitch.length > 0){
                var tmp = smd_pitch[0].split(/\s+/)
                signal_info[layer].smd_pitch = (tmp[2]/1000).toFixed(3);
            }else{
                signal_info[layer].smd_pitch = '/';
            }
            if(bga_pitch.length > 0){
                var tmp = bga_pitch[0].split(/\s+/)
                signal_info[layer].bga_pitch = (tmp[2]/1000).toFixed(3);
            }else{
                signal_info[layer].bga_pitch = '/';
            }		
            if(rout_copper.length > 0){
                var tmp = rout_copper[0].split(/\s+/)
                signal_info[layer].rout_copper = (tmp[2]/1000).toFixed(3);
            }else{
                signal_info[layer].rout_copper = '/';
            }
            IKM.save_layerinfo({jobid:JobId,
                            jobcategory:'org',
                            tlname:matrix[layer].tl_name,
                            layerinfohash:{l2l_min:signal_info[layer].line_to_line,
                                             l2p_min:signal_info[layer].line_to_pad,
                                             p2p_min:signal_info[layer].pad_to_pad,
                                             h2c_min:signal_info[layer].hole_to_copper,
                                             annular_ring_min:signal_info[layer].min_ring,
                                             org_line_width_min:signal_info[layer].min_line,
                                             rout_to_copper:signal_info[layer].rout_copper,
                                             smd_pitch:signal_info[layer].smd_pitch,
                                             bga_pitch:signal_info[layer].bga_pitch,
                                        }
                            });
        })
        pg_layers.forEach(function(layer){
            var pg_meas = GEN.getCheckMeas({job:job,step:step,chklist:check_list,nact:2,units:par.units,layer:layer});
           
            var hole_to_copper = pg_meas.filter(function(v){return /(via2l)|(via2c)|(pth2c)|(pth2l)/.test(v)})  // hole到copper
            var min_ring = pg_meas.filter(function(v){return /(via2t)|(pth2t)/.test(v)})  // 最小ring
            var rout_copper = pg_meas.filter(function(v){return /r2c/.test(v)})  // rout to copper
            if(!signal_info[layer]){signal_info[layer] = {}}
            
            if(hole_to_copper.length > 0){
                var tmp = hole_to_copper[0].split(/\s+/)
                signal_info[layer].hole_to_copper = (tmp[2]/1000).toFixed(3);
            }else{
                signal_info[layer].hole_to_copper = '/';
            }
            if(min_ring.length > 0){
                var tmp = min_ring[0].split(/\s+/)
                signal_info[layer].min_ring = (tmp[2]/1000).toFixed(3);
            }else{
                signal_info[layer].min_ring = '/';
            }
            if(rout_copper.length > 0){
                var tmp = rout_copper[0].split(/\s+/)
                signal_info[layer].rout_copper = (tmp[2]/1000).toFixed(3);
            }else{
                signal_info[layer].rout_copper = '/';
            }
            IKM.save_layerinfo({jobid:JobId,
                                jobcategory:'org',
                                tlname:matrix[layer].tl_name,
                                layerinfohash:{
                                        h2c_min:signal_info[layer].hole_to_copper,
                                        annular_ring_min:signal_info[layer].min_ring,
                                        rout_to_copper:signal_info[layer].rout_copper,
                                }}
                    );
        })


        sm_layers.forEach(function(layer){
            var sm_meas = GEN.getCheckMeas({job:job,step:step,chklist:check_list,nact:3,units:par.units,layer:layer});

            var pad_ring = sm_meas.filter(function(v){return /ar_pad/.test(v)})  // ring
            var pad_cover = sm_meas.filter(function(v){return /coverage/.test(v)})  // cover
            var pad_bridge = sm_meas.filter(function(v){return /pad2pad_bridge/.test(v)})  // bridge
            if(!signal_info[layer]){signal_info[layer] = {}}

            if(pad_ring.length > 0){
                var tmp = pad_ring[0].split(/\s+/)
                signal_info[layer].pad_ring = (tmp[2]/1000).toFixed(3);
            }else{
                signal_info[layer].pad_ring = '/';
            }
            if(pad_cover.length > 0){
                var tmp = pad_cover[0].split(/\s+/)
                signal_info[layer].pad_cover = (tmp[2]/1000).toFixed(3);
            }else{
                signal_info[layer].pad_cover = '/';
            }
            if(pad_bridge.length > 0){
                var tmp = pad_bridge[0].split(/\s+/)
                signal_info[layer].pad_bridge = (tmp[2]/1000).toFixed(3);
            }else{
                signal_info[layer].pad_bridge = '/';
            }
            IKM.save_layerinfo({jobid:JobId,
                                jobcategory:'org',
                                tlname:matrix[layer].tl_name,
                                layerinfohash:{
                                sm_bridge:signal_info[layer].pad_bridge,
                                sm_cover:signal_info[layer].pad_cover,
                                sm_annular_ring:signal_info[layer].pad_ring,
                        }}
            );
        })
        
        ss_layers.forEach(function(layer){
            var ss_meas = GEN.getCheckMeas({job:job,step:step,chklist:check_list,nact:4,units:par.units,layer:layer});
            var ss_line = ss_meas.filter(function(v){return /ss_line/.test(v)})  
            if(!signal_info[layer]){signal_info[layer] = {}}
            
            if(ss_line.length > 0){
                var tmp = ss_line[0].split(/\s+/)
                signal_info[layer].ss_min_line = (tmp[2]/1000).toFixed(3);
            }else{
                signal_info[layer].ss_min_line = '/';
            }
            IKM.save_layerinfo({jobid:JobId,
                                jobcategory:'org',
                                tlname:matrix[layer].tl_name,
                                layerinfohash:{
                                                    ss_min_line:signal_info[layer].ss_min_line,
                                            }}
            );
        })


        var result = save_drill_info({job:job,step:step,step_type:'pcs',jobcategory:'mi'});
        if (result){
            throw result;
        }
        saveMeans({job:job,step:step,chklist:check_list})
        GEN.clearLayers();
        GEN.affectedLayer( {mode:'all',affected:'no'} );
        GEN.closeStep()
    })
	// 保存 
	if(/yes/ig.test(par.auto_save)){GEN.checkInout({job:job,mode:"out"}); GEN.saveJob({ job: job });GEN.checkInout({job:job,mode:"in"});GEN.closeJob({job:job});} else {GEN.checkInout({job:job,mode:"in"})}
	if (mode === "aimdfm") {
		$.QDfm.updateRow({table: "pdm_aimdfm_task",data: {progress: 33.33},where: { id: $.task_id }});
		if (GEN.hasError()) { Status = 'error';resultData.push({ type: "error", title: "GEN错误!", detail: [{ desc: _.join(GEN.STATUS, "\n") }] });
			return {status: Status,result_data: resultData};
		} else { resultData.push({ type: "info", title: "操作完成, 请注意检查!" }); return {status: Status,result_data: resultData}; }
	}else { return "Done" }
} catch (e) {
	IKM.msg(_.join(GEN.STATUS, "\n"));IKM.msg(e);Status = 'error';
    resultData.push({type: "error", title: "脚本执行出错!", detail: [{desc: _.toString(e)}]});
    return (mode === "aimdfm") ? {status: Status, result_data: resultData} : "Error";
}



function UPLOAD_LAYER_MATRIX(props){
    var job = props.job
    props.jobcategory = props.jobcategory || "work"
    var matrix = ANALYSIS_STACKUP({job:job, jobcategory:props.jobcategory});
    Omatrix = matrix
    var layers = Object.keys(matrix).sort(function(a,b){return matrix[a]["row"] - matrix[b]["row"]})
    var tableName = "pdm_job_" + props.jobcategory + "_layer";
    console.log("===========>matrix upload");
    var oLayers = db.query("",function(q){
        return q.selectMapMap({
            table:tableName,
            field: ["odb_name", "release_status"],
            where:{job_id:JobId},
            uniquefield: "odb_name"
        })
    });
    db.query("",function(q){
        return q.deleteRow({
            table:tableName,
            where:{job_id:JobId},
        })
    });
    var fieldLst = ["name", "odb_context", "odb_type", "odb_polarity", "odb_side", "drl_start", "drl_end",
        "row_num", "type", "drl_start_num", "drl_end_num", "drl_from_num", "drl_to_num", "drl_connect_to",
        "odb_name", "side", "stackup_num", "customer_field", "input_file_name", "odb_row_num"
    ];
    layers.forEach(function(layer){
        var layerInfo = matrix[layer];
        var tmpData = {
            "job_id": JobId,
            "name": layerInfo["name"]
        };
        tmpData["release_status"] = (oLayers&&oLayers.hasOwnProperty(layerInfo["odb_name"])) ? oLayers[layerInfo["odb_name"]]["release_status"] : null;
        for (n = 0; n < fieldLst.length; n++) {
            tmpData[fieldLst[n]] = layerInfo[fieldLst[n]];
        }
        db.query("",function(q){
            return q.insertRow({
                table:tableName,
                data: tmpData
            })
        });
    })
    return matrix
}

function ANALYSIS_STACKUP(props){
    var job = props.job
    if(!props.hasOwnProperty("jobcategory")){ props.jobcategory = 'work' }
    var matrix = GEN.getMatrix({job:job})
    var layer_count = GEN.getLayerCount({job:job}) // !
    IKM.save_job_info({jobid:JobId,jobcategory:props.jobcategory,jobinfohash:{TL_layer_count:layer_count}})
	_.values(matrix).sort(function(a,b){return a.row-b.row}).forEach(function(layer){
        layer.odb_name = layer.name;
		layer.name = layer.tl_name;
		layer.odb_context = layer.context;
		layer.odb_type = layer.layer_type;
		layer.odb_polarity = layer.polarity;
		layer.odb_side = layer.side;
		layer.row_num = layer.tl_num;
		layer.type = layer.tl_type;
		layer.side = layer.enum_tl_side;
		layer.input_file_name = layer.file_name;
		layer.odb_row_num = layer.row;
		if (layer.odb_name == 'ftdrill'){
			layer.name = 'drill';
			layer.drl_start_num = 1;
			layer.drl_end_num = layer_count;
			layer.drl_from_num = 1;
			layer.drl_to_num = layer_count;
			layer.type = 'main_drill';
        }
		else if (/^ftdrill(\d+)-(\d+)/.test(layer.odb_name)){  // /^d(\d+)\-(\d+)$/
            var tmp = /^ftdrill(\d+)-(\d+)/.exec(layer.odb_name)
			var drl_star = tmp[1];
			var drl_end = tmp[2];
			layer.drl_start_num = drl_star;
			layer.drl_end_num = drl_end;
			layer.drl_from_num = drl_star;
            layer.drl_to_num = drl_end;
            if(drl_end - drl_star == 1){
                layer.name = 'laser' + drl_star + '-' + drl_end;
				layer.type = 'laser_drill';              // 镭射
            } else if( drl_star == 1 || drl_end == layer_count ){
                layer.name = 'drill' + drl_star + '-' + drl_end;
				layer.type = 'blind_drill';             // 埋孔
			} else{
                layer.name = 'drill' + drl_star + '-' + drl_end;
				layer.type = 'bury_drill';              // 盲孔
			}
		}
		else if (/\-a$/.test(layer.odb_name)){
            layer.side = 'top';
            if(!layer.name){
                layer.name = '__'+layer.odb_name+'__'
            }
            if(!layer.type){
                layer.type = 'other'
            }
		}
		else if (/\-b$/.test(layer.odb_name)){
            layer.side = 'bottom';
            if(!layer.name){
                layer.name = '__'+layer.odb_name+'__'
            }
            if(!layer.type){
                layer.type = 'other'
            }
		}
		else{
            if(!layer.name){
                layer.name = '__'+layer.odb_name+'__'
            }
			if(!layer.type){
                layer.type = 'other'
            }
		}
    })
    return matrix;
}



function save_drill_info(props){
	var job = props.job
	var step = props.step
	var matrix_ = GEN.getMatrix({job:job});
	var drill = [];
    // 获取工作层
    for (var key in matrix_) {
        if(matrix_[key].context == "board" && matrix_[key].tl_type=="drill") {
            drill.push(key)
        }
    }

	var matrix = ANALYSIS_STACKUP({job:job});
    var orgDrills = [];
    var miDrills = [];

    drill.forEach(function(drl) {
        if(drl) {
            var tool = GEN.getTool({job:job,step:step,layer:drl,units:PAR.unit});
            Object.keys(tool).sort(function(a,b){return tool[a].num - tool[b].num}).forEach(function(num){
                var toolInfo = tool[num]
                var orgDrillInfo = {
                    job_id		: JobId,
                    step_name	: step,
                    step_type	: props.step_type,
                    std_layer_name	: matrix[drl].name,
                    odb_layer_name	: drl,
                    row_num		: num,
                    drill_size	: toolInfo.finish_size / 1000,
                    finish_size	: toolInfo.finish_size / 1000,
                    drill_type	: toolInfo.type2 != 'standard' ? toolInfo.type2 : toolInfo.type,
                    drill_shape	: toolInfo.shape,
                    count		: toolInfo.count,
                    slot_length	: toolInfo.slot_len,
                    drill_size_lower_tol : toolInfo.min_tol,
                    drill_size_upper_tol : toolInfo.max_tol
                }
                var miDrillInfo = {
                    job_id		: JobId,
                    step_name	: step,
                    step_type	: props.step_type,
                    std_layer_name	: matrix[drl].name,
                    odb_layer_name	: drl,
                    row_num		: num,
                    drill_size	: toolInfo.drill_size  / 1000,
                    finish_size	: toolInfo.finish_size / 1000,
                    drill_type	: toolInfo.type2 != 'standard' ? toolInfo.type2 : toolInfo.type,
                    drill_shape	: toolInfo.shape,
                    count		: toolInfo.count,
                    slot_length	: toolInfo.slot_len,
                    drill_size_lower_tol : toolInfo.min_tol,
                    drill_size_upper_tol : toolInfo.max_tol
                };
                orgDrills.push(orgDrillInfo);
                miDrills.push(miDrillInfo);
            })
        }
    })

	var func = 'function(ARGV)\
	{\
		var jobId = ARGV["job_id"];\
		var data = ARGV["data"];\
		var midata = ARGV["midata"];\
		var stepName = ARGV["step_name"];\
		var tableName = "pdm_job_" + ARGV["jobcategory"] + "_drill";\
		//GUI.msgbox({text: TDataParse.variant2JsonStr(tableName)});\
		//GUI.msgbox({detail: _.toString(ARGV["data"])});\
		var db = new TSqlQueryV2(T_SQLCNT_POOL.getSqlDatabase());\
		db.begin();\
		try{\
			var miData = [];\
			var orgUidList = [];\
			_.each(data, function(h){\
				h.uid = TDataParse.getUuid();\
				orgUidList.push(h.uid);\
			});\
			var i = 0;\
			_.each(midata, function(n){\
				n.uid = TDataParse.getUuid();\
				var miMap = _.pick(n, ["job_id","std_layer_name","odb_layer_name","step_name","step_type","drill_size","finish_size","drill_type","drill_shape","drill_size_lower_tol","drill_size_upper_tol","slot_length"])\
				miMap.uid = TDataParse.getUuid();\
				if (n.step_type == "pcs") miMap.pcs_count = n.count;\
				if (n.step_type == "array") miMap.array_count = n.count;\
				miMap.calc_drill_size = n.drill_size;\
				miMap.org_size = n.finish_size;\
				miMap.org_slot_length = n.org_slot_length;\
				miMap.org_size_upper_tol = n.drill_size_upper_tol;\
				miMap.org_size_lower_tol = n.drill_size_lower_tol;\
				miMap.org_uids = [orgUidList[i]];\
				miData.push(miMap);\
				i++;\
			});\
			db.deleteRow({table: "pdm_job_org_drill", where: {job_id: jobId}});\
			db.batchInsert("pdm_job_org_drill", ["uid","job_id","step_name","step_type","std_layer_name","odb_layer_name","row_num","drill_size",\
			"drill_type","drill_shape","count","slot_length","drill_size_lower_tol","drill_size_upper_tol"], data);\
			if (ARGV["jobcategory"] == "mi") {\
				db.deleteRow({table: "pdm_job_mi_drill", where: {job_id: jobId, step_name: stepName}});\
				db.batchInsert("pdm_job_mi_drill", db.getFieldList("pdm_job_mi_drill"), miData);\
			}\
			if (db.lastError().isValid()) throw db.lastError();\
			db.commit();\
			return new TDataResponse();\
		}\
		catch (err)\
		{\
			GUI.msgbox({text: "Error", detail: _.toString(err.text())});\
			db.rollback();\
			return new TDataResponse(err, "");\
		}\
	}';
	var ret = IKM.command( func,{job_id :JobId, data:orgDrills,midata:miDrills,jobcategory:props.jobcategory,step_name:step}, 1); // --work属性
	if (ret.errText) {
		return {
			jobcategory:props.jobcategory,
			errText : ret.errText,
			errCode : ret.errCode,
		};
	}
}



function mkPath(path, list) {
	if (list.length) {
		var newPath = path + '/' + list.shift()
		if (!fs.dirExists(newPath)) {fs.mkdir(newPath)}
		return mkPath(newPath, list)
	} else {
		return path
	}
}
function saveMeans(props){
	var job = props.job
	var custstep = props.step
	var chklist = props.chklist
	var nact = props.nact
	var jobpath = GEN.getJobPath({job: job})
	var filter = props.filter
	var afterPath = mkPath(jobpath, ["user", "opencam", "steps"])
	var steps;
	if (custstep) {
		steps = [custstep]
	} else {
		steps = GEN.getStepList({job: job})
	}
	if(!steps || steps.length==0){
		return
	}
	steps.forEach(function (step) {
		var chkPath = mkPath(afterPath, [step, "chk"])
		var chks
		if (chklist) {chks = [chklist]}else {
			chks = GEN.getChecklist({job: job,step: step})
		}
		if(chks && chks.length){
			chks.forEach(function (item, i) {
				var afterChkPath = mkPath(chkPath, [item])
				var hdr = "{\n\
	\"title\": \"" + item + "\",\n\
	\"sequence\": " + (i + 1) + "\n\
}"
				fs.writeFile(afterChkPath + "/hdr", _.toString(hdr))
				var nacts = []
				if (nact) {
					nacts = [nact]
				} else {
					var nactCount = GEN.getChklistActCount({job:job,step:step,chklist:item})
					for (var i = 0; i < nactCount; i++) {
						nacts.push(i+1)
					}
				}
				if(nacts.length > 0){
					var actionPath = mkPath(afterChkPath, ["actions"])
					nacts.forEach(function(index){
						var titleFile = GEN.INFO({
							entity_type: "check",
							entity_path: job + "/" + step + "/" + item,
							data_type: "TITLE",
							options: "action=" + index,
							parse:'no'
						})
						var title = fs.readFile(titleFile)
						title = title.split("=")[1].trim()
						title = title.substring(1, title.length-1)
						var nackPath = mkPath(actionPath, [index+"-"+title]) 
						fs.writeFile(nackPath + "/hdr", "{\n\
	\"title\": \"" + (index + "-" + title) + "\",\n\
	\"sequence\": " + index + ",\n\
	\"dfm_name\": \"" + title + "\"\n\
}")
						var displayFile = GEN.INFO({
							entity_type: 'check',
							entity_path: job + "/" + step + "/" + item,
							data_type: 'MEAS_DISP_ID',
							options: "action=" + index,
							parse:'no'
						});
						fs.writeFile(nackPath + "/disp", fs.readFile(displayFile))
						var measFile = GEN.INFO({entity_type:'check', entity_path:job+'/'+step+'/'+item, data_type:'MEAS', options:"index+action="+index, parse:'no'});
						var means
						if(filter){  // 处理过滤
							var fileArray = []
							var file = fs.openFile(measFile,'r');
							while(!file.atEnd()) {
								fileArray.push(file.readLine())
							}
							if(Array.isArray(filter)){
								var nowFilter = filter.filter(function(item2){
									for (var key in item2) {
										var value = item2[key]
										if (!Array.isArray(value)){
											item2[key] = [value]
										}
									}
									return item2.step.indexOf(step)>=0 && item2.chk.indexOf(item)>=0 && item2.nact.indexOf(index)>=0
								})
								if (nowFilter.length > 0){
									var nowfilter = nowFilter.map(function(v){return v.filter}).reduce(function(a,b){
										b.forEach(function(v2){
											if (a.indexOf(v2)<0){
												a.push(v2)
											}
										})
										return a
									},[])
									fileArray = fileArray.filter(function(line){
										var flag = false
										nowfilter.forEach(function(f){
											var reg = new RegExp(f, "ig")
											if (reg.test(line)){
												flag = true
											}
										})
										return flag
									})
								}
							} else if (typeof filter == "object") {
								if (filter[step] && filter[step][item] && filter[step][item][String(index)]) {
									var nowFilter = filter[step][item][String(index)]
									if (!Array.isArray(nowFilter)){nowFilter = [nowFilter]}
									fileArray = fileArray.filter(function(line){
										var flag = false
										nowFilter.forEach(function(f){
											var reg = new RegExp(f, "ig")
											if (reg.test(line)){
												flag = true
											}
										})
										return flag
									})
								}
							}
							means = fileArray.join("\n")
						} else {
							means = fs.readFile(measFile)
						}
						fs.writeFile(nackPath + "/meas", means)
					})
				}
			})
		}
	})
}