private void ProcessSliceOnce(List<POINT> ptsAspOrg, List<double> volumes, string liquidClass ,
            int srcRackIndex,int sliceIndex, int sampleIndexInRack,StreamWriter sw)
        {
            //有时候,液体需要被喷到不同行,比如目标载架为4*6时
            bool inSameColumn = IsDstWellsInSameColumn(srcRackIndex, sampleIndexInRack, ptsAspOrg.Count);
            int srcGrid = GetSrcGrid(srcRackIndex);
            int globalSampleIndex = GetGlobalSampleIndex(srcRackIndex, sampleIndexInRack); //
            bool bNeedUseLastFour = NeedUseLastFour(sampleIndexInRack);
            List<POINT> ptsAsp = new List<POINT>(ptsAspOrg);
            if (bNeedUseLastFour)
            {
                POINT ptZero = new POINT(0, 0);
                ptsAsp.InsertRange(0, new List<POINT>() { ptZero, ptZero, ptZero, ptZero });
                volumes.InsertRange(0, new List<double>() { 0, 0, 0, 0 });
            }

            //2 吸,喷
            string strAspirate = GenerateAspirateCommand(ptsAsp, volumes, liquidClass, srcGrid,0, labwareSettings.sourceWells);
            sw.WriteLine(strAspirate);

            if (inSameColumn)
            {
                List<POINT> ptsDisp = positionGenerator.GetDestWells(srcRackIndex, sliceIndex, sampleIndexInRack, ptsAspOrg.Count);
                int grid = 0, site = 0;
                CalculateDestGridAndSite(globalSampleIndex, sliceIndex, ref grid, ref site);
                if(bNeedUseLastFour)
                {
                    POINT ptZero = new POINT(0, 0);
                    ptsDisp.InsertRange(0, new List<POINT>() { ptZero, ptZero, ptZero, ptZero });
                }
                string strDispense = GenerateDispenseCommand(ptsDisp, volumes, liquidClass, grid,site, labwareSettings.dstLabwareRows);
                sw.WriteLine(strDispense);
            }
            else
            {
                //throw new Exception("try to dispense to different regions.");
                int endIndexFirstColumn = GetEndIndexForFirstColumn(srcRackIndex, sampleIndexInRack);
                int firstColumnSampleCount = endIndexFirstColumn - srcRackIndex * labwareSettings.sourceWells - sampleIndexInRack + 1;
                List<POINT> ptsDisp = positionGenerator.GetDestWells(srcRackIndex,sliceIndex, sampleIndexInRack, firstColumnSampleCount);
                int grid = 0, site = 0;
                CalculateDestGridAndSite4OneSlicePerLabware(sliceIndex, ref grid, ref site);
                List<double> volumes1;
                List<double> volumes2;
                SplitVolumes2Region(volumes, out volumes1, out volumes2, firstColumnSampleCount);
                string strDispense = GenerateDispenseCommand(ptsDisp, volumes1, liquidClass, grid, site, labwareSettings.dstLabwareRows);
                sw.WriteLine(strDispense);
                int secondColumnStartSampleIndex = endIndexFirstColumn + 1;
                ptsDisp = positionGenerator.GetDestWells(srcRackIndex,sliceIndex, sampleIndexInRack + firstColumnSampleCount, ptsAsp.Count - firstColumnSampleCount);
                strDispense = GenerateDispenseCommand(ptsDisp, volumes2, liquidClass, grid, site, labwareSettings.dstLabwareRows);
                sw.WriteLine(strDispense);
            }
        }
        private void WriteDispenseBuffyNoCheck(List<POINT> pts, int grid,int site, StreamWriter sw, int tipOffset)
        {
            log.Info("WriteDispenseBuffy for certain region");
            int sampleCnt = pts.Count;
            int ditiMask = GetTipSelection(sampleCnt,tipOffset);
            List<double> vols = new List<double>();
            for(int i = 0; i < 8; i++)
            {
                vols.Add(0);
            }
            for( int i = 0; i< sampleCnt;i++)
            {
                if (tipOffset + i < 8)
                    vols[tipOffset + i] = 10;
            }

            WriteDispenseBuffyWithMovingPluger(pts,ditiMask,vols,grid,site,tipOffset,sw);
             //List<POINT> pts = positionGenerator.GetDestWellsForCertainSliceOfOneBatch(batchIndex,0,false);

            //WriteComment("Move tips up.", sw);
            //sw.WriteLine(sMoveLiha);

            List<double> volumes = new List<double>();
            //int startTip = 0;
            int buffySlice = pipettingSetting.dstbuffySlice;
            if (buffySlice > 1) //need dispense the buffy
            {
                volumes.Clear();
                for (int i = 0; i < tipOffset + sampleCnt; i++)
                {
                    if (i < tipOffset || buffySlice == 0)
                        volumes.Add(0);
                    else
                    {
                        volumes.Add(pipettingSetting.buffyVolume * (buffySlice - 1) / buffySlice);
                    }
                }
                WriteComment("aspirate buffy from slice 1", sw);
                if(tipOffset == 4) //use last four
                {
                    POINT ptZero = new POINT(0, 0);
                    pts.InsertRange(0, new List<POINT> { ptZero, ptZero, ptZero, ptZero });
                }
                string strAsp = GenerateAspirateCommand(pts, volumes, BB_Buffy_Mix, grid, site, labwareSettings.dstLabwareRows);
                sw.WriteLine(strAsp);

                for (int i = 0; i < volumes.Count; i++)
                    volumes[i] = volumes[i] / (buffySlice - 1);
                List<POINT> ptsDisp = new List<POINT>(pts);
                for (int slice = 1; slice < pipettingSetting.dstbuffySlice; slice++)
                {
                    int sliceUsedGrid = 0;
                    if (labwareSettings.dstLabwareColumns == 1)
                        sliceUsedGrid = slice;
                    else
                    {
                        ptsDisp = ChangePositions(pts, slice);
                    }
                    string strDispense = GenerateDispenseCommand(ptsDisp, volumes, BB_Buffy_Mix, grid + sliceUsedGrid, site, labwareSettings.dstLabwareRows);
                    WriteComment(string.Format("Dispensing buffy slice: {0}", slice + 1), sw);
                    sw.WriteLine(strDispense);
                }
            }
        }
        private void GenerateForBatch(string sOutput,int rackIndex, int sampleIndexInRack, List<DetectedInfo> heightsThisTime)
        {
            bool bNeedUseLastFour = NeedUseLastFour(sampleIndexInRack);
            log.InfoFormat("rack index : {0}, start sample : {1}", rackIndex, sampleIndexInRack);
             //batch index
            int batchID = 1+ sampleIndexInRack / labwareSettings.tipCount;

            int tipOffSet = GetTipOffSet(bNeedUseLastFour);
            int ditiMask = 0;
            for (int i = tipOffSet; i < tipOffSet + heightsThisTime.Count; i++)
                ditiMask += (int)Math.Pow(2, i);

            //create batch file
            string suffix = ".gwl";
            string sBatchFile = sOutput + string.Format("\\worklist{0}{1}",batchID,suffix);

            if (File.Exists(sBatchFile))
                File.Delete(sBatchFile);
            FileStream fs = new FileStream(sBatchFile, FileMode.CreateNew);
            StreamWriter sw = new StreamWriter(fs, Encoding.Default);
            sw.WriteLine("W;");

            string sNotifierFolder = Utility.GetExeFolder();

            //0 get diti
            WriteComment(string.Format("batch id is: {0}", batchID), sw);
            sw.WriteLine(string.Format(breakPrefix + "GetDiti2({0},\"DiTi 1000ul LiHa\",0,0,10,70);", ditiMask));

            //1 aspirate plasmas
            double area = mappingCalculator.GetArea();
            if(GlobalVars.Instance.IsRedCell)
            {
                pipettingSetting.dstbuffySlice = 0;
                mixCommand mixCommand = new mixCommand();
                List<int> vols = new List<int>();
                heightsThisTime.ForEach(x=>vols.Add((int)(mappingCalculator.GetVolumeFromHeight(x.Z1)-mappingCalculator.GetVolumeFromHeight(x.Z2))));
                var strs = mixCommand.GenerateMixForBatch(rackIndex,sampleIndexInRack,vols);
                strs.ForEach(s => sw.WriteLine(s));
            }
            List<POINT> ptsAsp = positionGenerator.GetSrcWells(sampleIndexInRack, heightsThisTime.Count);  //.GetSrcWellsForCertainSliceOfOneBatch(batchIndex);
            int plasmaSlice = pipettingSetting.dstPlasmaSlice;
            List<double> plasmaVols = new List<double>();
            for (int slice = 0; slice < plasmaSlice; slice++)
            {
                string sExe = sNotifierFolder + string.Format("Notifier.exe Pipetting;{0};{1};{2}", rackIndex,batchID-1, slice);
                if(sNotifierFolder != "")
                sw.WriteLine(string.Format(breakPrefix + "Execute(\"{0}\",2,\"\",2);", sExe));

                WriteComment(string.Format("Processing slice: {0}, plasma part", slice + 1), sw);
                plasmaVols = GenerateForSlice(slice, plasmaSlice,ptsAsp,rackIndex,sampleIndexInRack, heightsThisTime,sw);
                if(GlobalVars.Instance.TrackBarcode)
                    barcodeTracker.Track(plasmaVols,slice);
            }

            //2 aspirate & dispense buffy
            bool bhasBuffyCoat = pipettingSetting.dstbuffySlice > 0;//ResultReader.Instance.HasBuffyCoat();
            bool inSameColumn = IsDstWellsInSameColumn(rackIndex, sampleIndexInRack, ptsAsp.Count);
            int globalSampleIndex = GetGlobalSampleIndex(rackIndex, sampleIndexInRack);
            //int secondRegionStartSampleIndex = GetEndIndexForFirstRegion(rackIndex, startSample) + 1;

            if (bhasBuffyCoat)
            {
                string sExe = sNotifierFolder + string.Format("Notifier.exe Pipetting;{0};{1};{2}", rackIndex,batchID-1, pipettingSetting.dstPlasmaSlice);
                if(sNotifierFolder != "")
                sw.WriteLine(string.Format(breakPrefix + "Execute(\"{0}\",2,\"\",2);", sExe));
                //3 为buffy设置tipVolume
                List<double> buffyvolumes = new List<double>();

                if(bNeedUseLastFour)
                {
                    buffyvolumes.AddRange(new List<double> { 0, 0, 0, 0 });
                    POINT ptZero = new POINT(0, 0);
                    ptsAsp.InsertRange(0, new List<POINT>() { ptZero, ptZero, ptZero, ptZero });
                }
                for (int tipIndex = 0; tipIndex < heightsThisTime.Count; tipIndex++)
                {
                    buffyvolumes.Add(10); //为了让sample tracking起作用,加10ul
                }
                int srcGrid = GetSrcGrid(rackIndex);
                string strAspirateBuffy = GenerateAspirateCommand(ptsAsp, buffyvolumes, BB_Buffy, srcGrid, 0, labwareSettings.sourceWells);
                sw.WriteLine(strAspirateBuffy);

                //4 asp buffy using MSD
                WriteMSDCommands(sw, heightsThisTime, tipOffSet);

                //5 dispense buffy
                if (inSameColumn)
                {
                    WriteDispenseBuffy(rackIndex, sampleIndexInRack,  heightsThisTime.Count,bNeedUseLastFour,false, sw);
                }
                else//need to dispense to different column
                {
                    int endIndexFirstColumn = GetEndIndexForFirstColumn(rackIndex, sampleIndexInRack);
                    int firstColumnSampleCount = endIndexFirstColumn - rackIndex * labwareSettings.sourceWells - sampleIndexInRack + 1;
                    WriteDispenseBuffy(rackIndex, sampleIndexInRack, firstColumnSampleCount, bNeedUseLastFour, true, sw);
                    int secondColumnStartSampleIndex = endIndexFirstColumn + 1;
                    WriteDispenseBuffy(rackIndex, secondColumnStartSampleIndex, heightsThisTime.Count - firstColumnSampleCount, bNeedUseLastFour, true, sw);
                }
            }

            sw.WriteLine(string.Format(breakPrefix + "DropDiti({0},{1},2,10,70,0);", ditiMask,labwareSettings.wasteGrid));

            int endSampleID = rackIndex * 16 + sampleIndexInRack + heightsThisTime.Count;
            if (endSampleID >= detectInfos.Count)
            {
                string sFinishedCommand = sNotifierFolder + string.Format("Notifier.exe Pipetting;true");
                sw.WriteLine(string.Format(breakPrefix + "Execute(\"{0}\",2,\"\",2);", sFinishedCommand));
            }
            sw.Close();
        }