/// <summary>
        /// Read the complete file and classify his rows into Command and Header group
        /// </summary>
        /// <returns>Observable of status process</returns>
        public IObservable <StatusProcessDTO> ClassifyRows()
        {
            return(Observable.Create((IObserver <StatusProcessDTO> observer) =>
            {
                try
                {
                    var statusProcess = new StatusProcessDTO()
                    {
                        ProcessName = ConstantMessage.ParseProcessing
                    };
                    var lines = File.ReadAllLines(filePath);
                    rows = new List <GerberRow>(lines.Length);

                    for (var rowIndex = 0; rowIndex < lines.Length; rowIndex++)
                    {
                        var line = lines[rowIndex];
                        var type = line[0] == '%'
                            ? EGerberRowType.Header
                            : (
                            new char[] { 'G', 'X', 'Y', 'M' }.Contains(line[0])
                                ? (EGerberRowType?)EGerberRowType.Command
                                : null
                            );
                        if (type == null)
                        {
                            observer.OnError(new Exception(ConstantMessage.CommandUnknow));
                        }
                        else
                        {
                            rows.Add(new GerberRow
                            {
                                rowIndex = rowIndex,
                                rowText = line,
                                type = (EGerberRowType)type
                            });
                            statusProcess.Percent = rowIndex * 100 / rows.Count();
                            observer.OnNext(statusProcess);
                        }
                    }
                    observer.OnCompleted();
                }
                catch (Exception)
                {
                    observer.OnError(new Exception(ConstantMessage.UnexpectedError));
                }
                return () => { };
            }));
        }
        /// <summary>
        /// Compress data into GerberHeaderDTO and list of GerberDrawDTO
        /// It's two objects contain all necesary information for draw in screen or printer
        ///
        /// It support G01 draw command, it goin to support G02 and G03, G36 and G37.
        /// </summary>
        /// <returns>Observable of status process</returns>
        public IObservable <StatusProcessDTO> GenerateDataDraw()
        {
            return(Observable.Create((IObserver <StatusProcessDTO> observer) =>
            {
                try
                {
                    var statusProcess = new StatusProcessDTO()
                    {
                        ProcessName = ConstantMessage.DataDrawProcessing
                    };
                    GerberTraceDTO lastDrawInfo = new GerberTraceDTO
                    {
                        GCode = "G01",
                        ApertureMode = 2,
                        Aperture = 10,
                        IsLPDark = true,
                        AbsolutePointStart = new CoordinateDTO(0, 0),
                        AbsolutePointEnd = new CoordinateDTO(0, 0)
                    };

                    var rowIndex = 0;
                    var parseOk = true;
                    while (rowIndex < rows.Count && parseOk)
                    {
                        var r = rows[rowIndex];
                        rowIndex++;
                        switch (r.type)
                        {
                        case EGerberRowType.Command:
                            var startChar = r.rowText[0];
                            switch (startChar)
                            {
                            // Command
                            case 'G':
                            case 'X':
                            case 'Y':
                                switch (startChar == 'G'
                                            ? r.rowText.Substring(0, 3)
                                            : lastDrawInfo.GCode)
                                {
                                case "G04":             // Comments are ignored
                                case "G90":             // Absolute coordinate
                                    Header.isAbsolute = true;
                                    break;

                                case "G91":             // Relative coordinate
                                    Header.isAbsolute = false;
                                    break;

                                case "G70":             // Inch unit expressed in Micrometer
                                    Header.UnitInMicroMeters = 25400;
                                    break;

                                case "G71":             // Millimeter Unit expressed in Micrometer
                                    Header.UnitInMicroMeters = 1000;
                                    break;

                                case "G01":             // Linear mode
                                    var di = getDataDraw(r.rowText, lastDrawInfo);
                                    switch (di.ApertureMode)
                                    {
                                    case 1:
                                    case 3:
                                        Draws.Add(di);
                                        lastDrawInfo = di;
                                        break;

                                    case 2:                 // Mode 02 it just change lastCoordenate
                                        lastDrawInfo = di;
                                        break;
                                    }
                                    break;

                                case "G54":             // Aperture change
                                    lastDrawInfo = new GerberTraceDTO {
                                        GCode = lastDrawInfo.GCode,
                                        Aperture = int.Parse(r.rowText.Substring(4, 2)),
                                        ApertureMode = lastDrawInfo.ApertureMode,
                                        IsLPDark = lastDrawInfo.IsLPDark,
                                        AbsolutePointStart = lastDrawInfo.AbsolutePointStart,
                                        AbsolutePointEnd = lastDrawInfo.AbsolutePointEnd
                                    };
                                    break;

                                default:
                                    observer.OnError(new Exception(ConstantMessage.CommandUnknow));
                                    parseOk = false;
                                    break;
                                }
                                break;

                            // End
                            case 'M':
                                // M00 and M01 are deprecated
                                if (r.rowText.Equals("M02*"))
                                {
                                    observer.OnCompleted();
                                }
                                else
                                {
                                    observer.OnError(new Exception(ConstantMessage.CommandUnknow));
                                    parseOk = false;
                                }
                                break;

                            default:
                                observer.OnError(new Exception(ConstantMessage.CommandUnknow));
                                parseOk = false;
                                break;
                            }
                            break;

                        case EGerberRowType.Header:
                            switch (r.rowText.Substring(1, 2))
                            {
                            // Format Specification
                            case "FS":
                                var reFS = new Regex(@"^%FS([L|T])([A|I])X(\d)(\d)Y\3\4\*%$");
                                var groupsFS = reFS.Matches(r.rowText)[0].Groups;
                                Header.isLeadingZeroOmission = groupsFS[1].Value.Equals("L");
                                Header.isAbsolute = groupsFS[2].Value.Equals("A");
                                Header.LeadingDigits = int.Parse(groupsFS[3].Value);
                                Header.TrailingDigits = int.Parse(groupsFS[4].Value);
                                break;

                            // Aperture Definition
                            case "AD":
                                var reAD = new Regex(@"^%ADD([1-9]\d+)([C|R|O|P]{1}),(?:([\d]*[\.][\d]*)X?)+\*%$");
                                var groupsAD = reAD.Matches(r.rowText)[0].Groups;
                                var aperture = new GerberApertureDTO
                                {
                                    Aperture = int.Parse(groupsAD[1].Value),
                                    Shape = groupsAD[2].Value[0]
                                };
                                foreach (Capture c in groupsAD[3].Captures)
                                {
                                    var valueUnit = double.Parse(c.Value, CultureInfo.InvariantCulture);
                                    var value = (int)(valueUnit * Math.Pow(10, Header.TrailingDigits));
                                    aperture.Modifiers.Add(value);
                                }
                                Header.Apertures.Add(aperture);
                                break;

                            default:
                                observer.OnError(new Exception(ConstantMessage.CommandUnknow));
                                parseOk = false;
                                break;
                            }
                            break;
                        }
                        statusProcess.Percent = rowIndex * 100 / rows.Count();
                        observer.OnNext(statusProcess);
                    }
                }
                catch (Exception)
                {
                    observer.OnError(new Exception(ConstantMessage.UnexpectedError));
                }
                return () => { };
            }));
        }