protected override void OnStart(string[] args)
        {
            //Grab those creds
            var creds = CredentialsManager.GetCreds(loggingSVC: svc);

            currentAccount = creds.Email;

            //Start up Firebase service
            svc = new SVCFirebase(creds.Key, creds.Email, creds.Password);

            //Initialize the folder watcher
            folderWatcher = new FileSystemWatcher(printerOutputFolderPath)
            {
                NotifyFilter = NotifyFilters.LastWrite   //Only observe writes to the directory
            };
            //Add event handlers
            folderWatcher.Changed += new FileSystemEventHandler(OnChangedEvent);
            folderWatcher.Created += new FileSystemEventHandler(OnChangedEvent);

            //Start watching
            folderWatcher.EnableRaisingEvents = true;

            //Start the heartbeat
            timer = new System.Timers.Timer
            {
                Interval = 1000 * 60 * 60   //Every hour
            };
            timer.Elapsed += new System.Timers.ElapsedEventHandler(SendHeartbeat);
            timer.Start();
        }
        public static Ticket Parse(FileStream file, FileInfo info, SVCFirebase loggingSvc)
        {
            try
            {
                //Read it all
                var ticketRaw = File.ReadAllText(info.FullName);

                //Extract the line with the order number and the order type
                var delim      = "Order #: ";
                var delimStart = ticketRaw.IndexOf(delim);
                var delimEnd   = ticketRaw.IndexOf("\n", delimStart);
                var rawInfo    = ticketRaw.Substring(delimStart + delim.Length, delimEnd - delimStart - delim.Length);

                //Extract the order number
                var firstSpace  = rawInfo.IndexOf(" ");
                var orderNumStr = rawInfo.Substring(0, firstSpace);

                //Extract order kind
                var excludeOrderNum = rawInfo.Substring(firstSpace, rawInfo.Length - firstSpace);
                var kind            = excludeOrderNum.Trim(' ', '\r', '\n').Replace(" ", "");

                //Extract the date
                DateTime?date = null;
                try
                {
                    var dateRegX = new Regex(@"\d+\/\d+\/\d+ \d+:\d+:\d+ (AM|PM)");
                    var match    = dateRegX.Match(ticketRaw);
                    date = DateTime.Parse(match.ToString());
                }
                catch (Exception e)
                {
                    loggingSvc.LogEvent("TicketParserError: " + e.Message);
                }
                return(new Ticket {
                    OrderNumber = orderNumStr, OrderKind = kind, Timestamp = date
                });
            }
            catch (Exception e)
            {
                loggingSvc.LogEvent("TicketParser Error: " + e.Message);
            }
            return(null);
        }
        public static Credentials GetCreds(SVCFirebase loggingSVC)
        {
            var path = GetCredDocPath();

            //Check if credentials file exists
            if (!File.Exists(path))
            {
                //If the file doesn't exist, try to create it
                try
                {
                    //Create the JSON template for someone to fill out later
                    var template = new Credentials {
                        Key = "", Email = "", Password = ""
                    };

                    //Create the file, write the JSON in, then close the file
                    File.WriteAllText(path, JsonConvert.SerializeObject(template));
                }
                catch (Exception e)
                {
                    loggingSVC.LogEvent("Couldn't create cred file because: " + e.Message);
                    return(null);
                }
            }
            //Read the cred file and extract creds
            try
            {
                var credFileContents = File.ReadAllText(path);
                if (DetectsPossibleEncryptionFor(credFileContents))
                {
                    credFileContents = EncryptionBlackBox(credFileContents);    //If possibly encrypted, try decrpyting
                }
                var result = JsonConvert.DeserializeObject <Credentials>(credFileContents);
                File.WriteAllText(path, EncryptionBlackBox(credFileContents));  //If deserialization worked, then re-encrpyt the file
                return(result);
            }
            catch (Exception e)
            {
                loggingSVC.LogEvent("Couldn't read cred file because: " + e.Message);
                return(null);
            }
        }
        private void OnChangedEvent(object sender, FileSystemEventArgs e)
        {
            //FileSystemWatcher will fire the event multiple times even for just one file, so this bool limits it
            if (!IsBusy())
            {
                SetBusy(true);

                var dirInfo = new DirectoryInfo(printerOutputFolderPath);
                var fileAr  = dirInfo.GetFiles().ToArray();
                files = new LinkedList <FileInfo>(fileAr);

                //If there's nothing in the directory, just stop
                if (files.Count == 0)
                {
                    SetBusy(false);
                    return;
                }
                new Thread(async() =>
                {
                    FileStream currentFile = null;
                    var attemptCount       = 0;
                    var attemptLimit       = 10;

                    //Do this stuff until the batch is empty
                    while (files.Count != 0)
                    {
                        //Try to open a file, but give up if the file can't be opened after a certain amount of attempts
                        while (currentFile == null && attemptCount < attemptLimit)
                        {
                            attemptCount += 1;
                            Thread.Sleep(3000); //Wait a bit because if not, then this program'll sometimes delete the data before it can actually make it to the printer
                            currentFile = TryToOpen(files.First.Value.FullName);
                            if (currentFile == null)
                            {
                                Thread.Sleep(500);
                            }
                        }
                        attemptCount = 0;   //Reset this immediately since the while loop is done with it

                        if (currentFile != null && files.First.Value != null)
                        {
                            await ProcessAsync(currentFile, files.First.Value);
                        }
                        //Clean up for next loop
                        currentFile = null;
                        files.RemoveFirst();
                    }
                    SetBusy(false); //Now that all the files in the batch have been processed and removed from the linked list, the program isn't busy anymore

                    //One more thing, if the directory still contains SHD or SPL files, it's not done, so call again
                    var leftoverFiles = GetFiles(printerOutputFolderPath, ".SHD", ".SPL");
                    if (leftoverFiles.Count != 0)
                    {
                        Thread.Sleep(1000);
                        if (SVCFirebase.ThereIsInternet()) //Oh, but don't keep retrying if there's no internet
                        {
                            OnChangedEvent(null, null);    //Recursive call again
                        }
                    }
                }).Start();
            }
        }