public Dictionary<string, PDFField> GetPDFFormFields(PdfReader document, bool includeValues)
        {
            Dictionary<string, PDFField> pdfFormFields = new Dictionary<string, PDFField>();

            foreach (KeyValuePair<string, AcroFields.Item> de in document.AcroFields.Fields)
            {
                PDFField pdffield = new PDFField();

                AcroFields.Item field = de.Value;
                PdfDictionary dic = field.GetWidget(0);

                //check for blank sig blocks
                //document.AcroFields.GetBlankSignatureNames

                pdffield.TypeId = document.AcroFields.GetFieldType(de.Key);
                pdffield.Type = GetPDFFieldType(document.AcroFields.GetFieldType(de.Key));
                //pdffield.IsRequired = ??;
                //pdffield.IsReadOnly = ??;
                pdffield.FullName = de.Key;
                pdffield.AlternativeName = de.Key;

                PdfString ps = dic.GetAsString(PdfName.TU);
                if (ps != null)
                {
                    pdffield.PartialName = ps.ToString();
                }

                string fieldvalue = string.Empty;

                if (includeValues)
                {
                    fieldvalue = document.AcroFields.GetField(de.Key);
                }
                pdffield.FieldValue = fieldvalue;

                pdfFormFields.Add(pdffield.FullName, pdffield);
            }

            return pdfFormFields;
        }
        /// <summary>
        /// Executes the Service Object method and returns any data.
        /// </summary>
        /// <param name="inputs">A Property[] array containing all the allowed input properties.</param>
        /// <param name="required">A RequiredProperties collection containing the required properties.</param>
        /// <param name="returns">A Property[] array containing all the allowed return properties.</param>
        /// <param name="methodType">A MethoType indicating what type of Service Object method was called.</param>
        /// <param name="serviceObject">A ServiceObject containing populated properties for use with the method call.</param>
        public void Execute(Property[] inputs, RequiredProperties required, Property[] returns, SourceCode.SmartObjects.Services.ServiceSDK.Types.MethodType methodType, ServiceObject serviceObject)
        {
            #region Get All Field Values

            if (serviceObject.Methods[0].Name.Equals("getallfieldvalues"))
            {
                serviceObject.Properties.InitResultTable();

                // get input field value
                string pdfuri = inputs.Where(p => p.Name.Equals("pdfuri")).FirstOrDefault().Value.ToString();

                PDFInfo info = new PDFInfo();
                Dictionary<string, PDFField> fields = new Dictionary<string, PDFField>();

                try
                {
                    using (PdfReader doc = new PdfReader(pdfUri))
                    {
                        // discover pdf doc
                        info = GetPDFDoucmentInformation(doc);
                        fields = GetPDFFormFields(doc, true);
                    }
                }
                catch(Exception ex)
                {
                    throw new Exception(string.Format("Error retrieving PDF document from {0}. Exception: {1}", pdfuri, ex.Message));
                }

                returns.Where(p => p.Name.Equals("pdfuri")).FirstOrDefault().Value = pdfuri;

                foreach(Property prop in returns)
                {
                    PDFField fieldvalue = new PDFField();

                    string fullname = string.Empty;

                    object pfn = prop.MetaData.ServiceProperties["pdffullname"];
                    if (pfn == null)
                    {
                        fullname = prop.Name;
                    }
                    else
                    {
                        fullname = pfn.ToString();
                    }

                    if (fields.TryGetValue(fullname, out fieldvalue))
                    {
                        prop.Value = fieldvalue.FieldValue;
                    }
                }

                Type type = typeof(PDFInfo);
                PropertyInfo[] props = type.GetProperties();
                foreach (var p in props)
                {
                    object v = info.GetType().GetProperty(p.Name).GetValue(info, null);
                    if (v != null)
                    {
                        string value = v.ToString();
                        returns.Where(q => q.Name.Equals(p.Name)).First().Value = value;
                    }
                }

                serviceObject.Properties.BindPropertiesToResultTable();

            }

            #endregion Get All Field Values

            #region Contains Signatures

            if (serviceObject.Methods[0].Name.Equals("containssignatures"))
            {
                serviceObject.Properties.InitResultTable();

                // get input field value
                string pdfuri = inputs.Where(p => p.Name.Equals("pdfuri")).FirstOrDefault().Value.ToString();

                PDFInfo info = new PDFInfo();
                Dictionary<string, PDFField> fields = new Dictionary<string, PDFField>();

                bool containssigs = false;

                try
                {
                    using (PdfReader doc = new PdfReader(pdfUri))
                    {
                        fields = GetPDFFormFields(doc, true);
                        containssigs = ContainsSignatures(fields);
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception(string.Format("Error retrieving PDF document from {0}. Exception: {1}", pdfuri, ex.Message));
                }

                returns.Where(p => p.Name.Equals("pdfuri")).FirstOrDefault().Value = pdfuri;
                returns.Where(p => p.Name.Equals("containssignatures")).FirstOrDefault().Value = containssigs;

                serviceObject.Properties.BindPropertiesToResultTable();

            }

            #endregion Contains Signatures

            #region Contains Unsigned Signatures

            if (serviceObject.Methods[0].Name.Equals("containsunsignedsignatures"))
            {
                serviceObject.Properties.InitResultTable();

                // get input field value
                string pdfuri = inputs.Where(p => p.Name.Equals("pdfuri")).FirstOrDefault().Value.ToString();

                PDFInfo info = new PDFInfo();
                Dictionary<string, PDFField> fields = new Dictionary<string, PDFField>();

                bool containsunsignedsigs = false;

                try
                {
                    using (PdfReader doc = new PdfReader(pdfUri))
                    {
                        containsunsignedsigs = ContainsBlankSignatures(doc);
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception(string.Format("Error retrieving PDF document from {0}. Exception: {1}", pdfuri, ex.Message));
                }

                returns.Where(p => p.Name.Equals("pdfuri")).FirstOrDefault().Value = pdfuri;
                returns.Where(p => p.Name.Equals("containsunsignedsignatures")).FirstOrDefault().Value = containsunsignedsigs;

                serviceObject.Properties.BindPropertiesToResultTable();

            }

            #endregion Contains Signatures

            #region Update PDF Field

            if (serviceObject.Methods[0].Name.Equals("updatepdffields"))
            {
                serviceObject.Properties.InitResultTable();

                // get input field value
                string pdfuri = inputs.Where(p => p.Name.Equals("pdfuri")).FirstOrDefault().Value.ToString();
                bool base64 = false;
                string base64temp = inputs.Where(p => p.Name.Equals("returnbase64")).FirstOrDefault().Value.ToString();
                bool.TryParse(base64temp, out base64);

                string workingFolder = serviceBroker.Service.ServiceConfiguration["WorkingFolder"].ToString();
                if (workingFolder.LastIndexOf(@"\") != workingFolder.Length - 1)
                {
                    workingFolder += @"\";
                }
                string filename = Guid.NewGuid().ToString()+".pdf";
                string workingPath = workingFolder + filename;

                PDFInfo info = new PDFInfo();
                Dictionary<string, PDFField> fields = new Dictionary<string, PDFField>();

                Dictionary<string, string> updates = new Dictionary<string, string>();
                foreach (Property prop in inputs)
                {
                    object pfn = prop.MetaData.ServiceProperties["pdffullname"];
                    if (!prop.Name.Equals("pdfuri") && pfn != null)
                    {
                        if (prop.Value != null)
                        {
                            updates.Add(pfn.ToString(), prop.Value.ToString());
                        }
                    }
                }

                if (updates.Count > 0)
                {
                    // call update method
                    using (PdfReader doc = new PdfReader(pdfuri))
                    {
                        // last parameter ensures that extended document properties are retained

                        using (PdfStamper pdfStamper = new PdfStamper(doc, new FileStream(workingPath, FileMode.Create), '\0', true))
                        {
                            AcroFields pdfFormFields = pdfStamper.AcroFields;
                            foreach (KeyValuePair<string, string> val in updates)
                            {
                                pdfFormFields.SetField(val.Key, val.Value);
                            }
                            pdfStamper.FormFlattening = false;
                            pdfStamper.Close();
                        }
                    }
                }

                returns.Where(p => p.Name.Equals("pdfuri")).FirstOrDefault().Value = pdfuri;
                returns.Where(p => p.Name.Equals("returnpath")).FirstOrDefault().Value = workingPath;
                returns.Where(p => p.Name.Equals("returnbase64")).FirstOrDefault().Value = base64;

                // read created doc
                try
                {
                    using (PdfReader doc = new PdfReader(workingPath))
                    {
                        // discover pdf doc
                        info = GetPDFDoucmentInformation(doc);
                        fields = GetPDFFormFields(doc, true);
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception(string.Format("Error retrieving PDF document from {0}. Exception: {1}", workingPath, ex.Message));
                }

                foreach (Property prop in returns)
                {
                    PDFField fieldvalue = new PDFField();

                    string fullname = string.Empty;

                    object pfn = prop.MetaData.ServiceProperties["pdffullname"];
                    if (pfn == null)
                    {
                        fullname = prop.Name;
                    }
                    else
                    {
                        fullname = pfn.ToString();
                    }

                    if (fields.TryGetValue(fullname, out fieldvalue))
                    {
                        prop.Value = fieldvalue.FieldValue;
                    }
                }

                Type type = typeof(PDFInfo);
                PropertyInfo[] props = type.GetProperties();
                foreach (var p in props)
                {
                    object v = info.GetType().GetProperty(p.Name).GetValue(info, null);
                    if (v != null)
                    {
                        string value = v.ToString();
                        returns.Where(q => q.Name.Equals(p.Name)).First().Value = value;
                    }
                }

                // get base64 of file
                if (base64)
                {
                    FileStream fs = new FileStream(workingPath, FileMode.Open, FileAccess.Read);
                    byte[] filebytes = new byte[fs.Length];
                    fs.Read(filebytes, 0, Convert.ToInt32(fs.Length));
                    string encodedData = Convert.ToBase64String(filebytes);
                    returns.Where(p => p.Name.Equals("base64pdf")).FirstOrDefault().Value = encodedData;
                }

                serviceObject.Properties.BindPropertiesToResultTable();
                return;
            }

            #endregion Update PDF Field

            #region Generate Create Table SQL

            if (serviceObject.Methods[0].Name.Equals("generatecreatetablesql"))
            {
                serviceObject.Properties.InitResultTable();

                string pdfuri = serviceBroker.Service.ServiceConfiguration["pdfUri"].ToString();

                PDFInfo info = new PDFInfo();
                Dictionary<string, PDFField> fields = new Dictionary<string, PDFField>();

                string sql = string.Empty;

                try
                {
                    using (PdfReader doc = new PdfReader(pdfUri))
                    {
                        info = GetPDFDoucmentInformation(doc);
                        fields = GetPDFFormFields(doc, false);
                        sql = GenerateCreateTableSQL(info, fields);
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception(string.Format("Error generating create table SQL from {0}. Exception: {1}", pdfuri, ex.Message));
                }

                returns.Where(p => p.Name.Equals("generatedsql")).FirstOrDefault().Value = sql;

                serviceObject.Properties.BindPropertiesToResultTable();

            }

            #endregion Generate Create Table SQL

            #region Copy Form Data to SmartObject

            if (serviceObject.Methods[0].Name.Equals("copyformdatatosmartobject"))
            {
                serviceObject.Properties.InitResultTable();

                string pdfuri = inputs.Where(p => p.Name.Equals("pdfuri")).FirstOrDefault().Value.ToString();
                string smoname = inputs.Where(p => p.Name.Equals("formstoresmartobjectname")).FirstOrDefault().Value.ToString();
                string smometh = inputs.Where(p => p.Name.Equals("formstoremethodname")).FirstOrDefault().Value.ToString();
                string returnprop = inputs.Where(p => p.Name.Equals("returnidpropertyname")).FirstOrDefault().Value.ToString();

                string returnvalue = string.Empty;

                PDFInfo info = new PDFInfo();
                Dictionary<string, PDFField> fields = new Dictionary<string, PDFField>();

                try
                {
                    using (PdfReader doc = new PdfReader(pdfUri))
                    {
                        info = GetPDFDoucmentInformation(doc);
                        fields = GetPDFFormFields(doc, true);
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception(string.Format("Error retrieving PDF document from {0}. Exception: {1}", pdfuri, ex.Message));
                }

                string returnId = string.Empty;
                try
                {
                    returnId = Utilities.SmartObjectUtils.CreateDataFromPDFForm(smoname, smometh, returnprop, info, fields);
                }
                catch (Exception ex)
                {
                    throw new Exception(string.Format("Error updated SmartObject from PDF document from {0}. Exception: {1}", pdfuri, ex.Message));
                }

                returns.Where(p => p.Name.Equals("pdfuri")).FirstOrDefault().Value = pdfuri;
                returns.Where(p => p.Name.Equals("formstoresmartobjectname")).FirstOrDefault().Value = smoname;
                returns.Where(p => p.Name.Equals("formstoremethodname")).FirstOrDefault().Value = smometh;
                returns.Where(p => p.Name.Equals("returnidpropertyname")).FirstOrDefault().Value = returnprop;
                returns.Where(p => p.Name.Equals("returnid")).FirstOrDefault().Value = returnId;

                serviceObject.Properties.BindPropertiesToResultTable();

            }

            #endregion Copy Form Data to SmartObject
        }