ViewerPdfInputTypes.cs
//
// This code is part of Document Solutions for PDF demos.
// Copyright (c) MESCIUS inc. All rights reserved.
//
using System.IO;
using System.Drawing;
using GrapeCity.Documents.Pdf;
using GrapeCity.Documents.Text;
using GrapeCity.Documents.Pdf.AcroForms;
using System.Collections.Generic;
using GrapeCity.Documents.Pdf.Spec;

namespace DsPdfWeb.Demos
{

    // This sample demonstrates using the GcPdfViewer's Form Filler
    // to load PDF form created by using DsPdf or GcExcel (containing custom input types).

    // This and other samples in this section demonstrate the features of GcPdfViewer
    // (a JavaScript PDF viewer control included with DsPdf), mainly the ability
    // to change PDF files (add or edit annotations and AcroForm fields, rotate pages etc.)
    // when the JS viewer on the client is supported by DsPdf running on the server.
    //
    // To enable the editing features of the viewer, its supportApi property must be set
    // to a URL on the server that implements all or some of the edit supporting APIs
    // that are known to/expected by the viewer. This DsPdf demo site provides those APIs,
    // which makes it possible to demonstrate the editing when you open the PDF viewer
    // in this sample. When you download this sample, in addition to the .NET Core
    // console app project that generates the sample PDF, an ASP.NET Core project is
    // also included in the download zip (located in the GcPdfViewerWeb sub-folder of the
    // downloaded zip), which also provides the necessary APIs. In particular, it includes
    // a project that implements the APIs and provides them via a special controller.
    // It is actually the same controller that is used by this DsPdf demo site, and which
    // can be used in any ASP.NET Core site to enable the viewer editing features.
    //
    // Look at the following files in the sample download zip for more info:
    // - GcPdfViewerWeb\SupportApiDemo: the sample ASP.NET Core web site.
    // - GcPdfViewerWeb\SupportApiDemo.sln: solution to build/run the sample web site.
    // - GcPdfViewerWeb\SupportApi: support API implementation (can be used in any site).
    // - GcPdfViewerWeb\SupportApi\Controllers\GcPdfViewerController.cs: support API controller.
    // 
    // Please note that this and other samples in this section are only available in C# at this time.
    //
    public class ViewerPdfInputTypes
    {
        public void CreatePDF(Stream stream)
        {
            CreateFormFieldsPDF(stream);
        }

        private Dictionary<string, KeyValuePair<string, object>[]> GetSampleGcPropTextFields()
        {


            return new Dictionary<string, KeyValuePair<string, object>[]>() {
                {
                    "date", new KeyValuePair<string, object>[]{
                    new KeyValuePair<string, object>("type", "date"),
                    new KeyValuePair<string, object>("placeholder", "Input date")}
                },
                {
                    "read-only date", new KeyValuePair<string, object>[]{
                        new KeyValuePair<string, object>("type", "date"),
                        new KeyValuePair<string, object>("defaultvalue", "2018-01-01"),
                        new KeyValuePair<string, object>("readonly", true)
                    }
                },
                {
                    "time", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "time") }
                },
                {
                    "time with default value", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "time"),
                    new KeyValuePair<string, object>("defaultvalue", "18:00") }
                },
                {
                    "tel", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "tel"),
                    new KeyValuePair<string, object>("validateoninput", true) }
                },
                {
                    "tel with pattern", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "tel"),
                    new KeyValuePair<string, object>("pattern", @"^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$"),
                    new KeyValuePair<string, object>("validateoninput", true),
                    new KeyValuePair<string, object>("validationmessage", "Valid formats:" +
                        "(123) 456-7890" +
                        "(123)456-7890" +
                        "123-456-7890" +
                        "123.456.7890" +
                        "1234567890" +
                        "+31636363634" +
                        "075-63546725") }
                },
                {
                    "email", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "email"),
                    new KeyValuePair<string, object>("autocomplete", "email"),
                    new KeyValuePair<string, object>("validateoninput", true) }
                },
                {
                    "multiple emails", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "email"),
                    new KeyValuePair<string, object>("autocomplete", "email"),
                    new KeyValuePair<string, object>("validateoninput", true),
                    new KeyValuePair<string, object>("multiple", true) }
                },
                {
                    "emails with pattern", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "email"),
                    new KeyValuePair<string, object>("pattern", @"\S+@example\.com"),
                    new KeyValuePair<string, object>("autocomplete", "email"),
                    new KeyValuePair<string, object>("placeholder", "Expected domain @example.com."),
                    new KeyValuePair<string, object>("validationmessage", "test@example.com."),
                    new KeyValuePair<string, object>("validateoninput", true),
                    new KeyValuePair<string, object>("multiple", true) }
                },
                {
                    "url", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "url"),
                    new KeyValuePair<string, object>("autocomplete", "url"),
                    new KeyValuePair<string, object>("validateoninput", true) }
                },
                {
                    "password", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "password"),
                    new KeyValuePair<string, object>("autocomplete", "new-password"),
                    new KeyValuePair<string, object>("validateoninput", true)  }
                },
                {
                    "password with minlength", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "password"),
                    new KeyValuePair<string, object>("placeholder", "minlength=8"),
                    new KeyValuePair<string, object>("minlength", 8),
                    new KeyValuePair<string, object>("validateoninput", true),
                    new KeyValuePair<string, object>("autocomplete", "new-password")} },
                {
                    "password with maxlength", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "password"),
                    new KeyValuePair<string, object>("placeholder", "maxlength=4"),
                    new KeyValuePair<string, object>("maxlength", 4),
                    new KeyValuePair<string, object>("validateoninput", true),
                    new KeyValuePair<string, object>("autocomplete", "off")} },
                {
                    "password with pattern", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "password"),
                    new KeyValuePair<string, object>("placeholder", "4 to 8 characters"),
                    new KeyValuePair<string, object>("pattern", @"^(?=.*\d).{4,8}$"),
                    new KeyValuePair<string, object>("validateoninput", true),
                    new KeyValuePair<string, object>("validationmessage",  "The password must be between 4 and 8 characters."),
                    new KeyValuePair<string, object>("autocomplete", "off")}
                },
                {
                    "password PIN", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "password"),
                    new KeyValuePair<string, object>("title", "Input your PIN"),
                    new KeyValuePair<string, object>("placeholder", "PIN"),
                    new KeyValuePair<string, object>("pattern", @"^[0-9]{3,3}$"),
                    new KeyValuePair<string, object>("maxlength", 3),
                    new KeyValuePair<string, object>("validateoninput", true),
                    new KeyValuePair<string, object>("validationmessage", "PIN password must be 3 digits."),
                    new KeyValuePair<string, object>("autocomplete", "one-time-code")}
                },
                {
                    "text with autofocus", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "text"),
                    new KeyValuePair<string, object>("autofocus", "true") }
                },
                {
                    "required text", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "text"),
                    new KeyValuePair<string, object>("required", true),
                    new KeyValuePair<string, object>("validateoninput", true) }
                },
                {
                    "text, spellcheck='true'", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "text"),
                    new KeyValuePair<string, object>("defaultvalue", "mistaake"),
                    new KeyValuePair<string, object>("spellcheck", "true")}
                },
                {
                    "text, spellcheck='false'", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "text"),
                    new KeyValuePair<string, object>("defaultvalue", "mistaake"),
                    new KeyValuePair<string, object>("spellcheck", "false")}
                },
                {
                    "month", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "month") }
                },
                {
                    "week", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "week") }
                },
                {
                    "number with min/max", new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("type", "number") ,
                    new KeyValuePair<string, object>("placeholder", "number"),
                    new KeyValuePair<string, object>("required", true),
                    new KeyValuePair<string, object>("title", "Please enter a number between 1 and 100"),
                    new KeyValuePair<string, object>("min", 1),
                    new KeyValuePair<string, object>("max", 100),
                    new KeyValuePair<string, object>("validateoninput", true),
                    new KeyValuePair<string, object>("validationmessage", "Expected number from 1 to 100") }
                },
                {
                    "search", new KeyValuePair<string, object>[] { new KeyValuePair<string, object>("type", "search") }
                },
                {
                    "range", new KeyValuePair<string, object>[] { new KeyValuePair<string, object>("type", "range"),
                        new KeyValuePair<string, object>("title", "Please select a number between 1 and 100"),
                        new KeyValuePair<string, object>("defaultvalue", 50),
                        new KeyValuePair<string, object>("min", 1),
                        new KeyValuePair<string, object>("max", 100)}
                },
                {
                "color", new KeyValuePair<string, object>[] { new KeyValuePair<string, object>("type", "color"),
                    new KeyValuePair<string, object>("title", "Please select a color"),
                    new KeyValuePair<string, object>("defaultvalue", "#385dab") }
                }
            };
        }

        public void CreateFormFieldsPDF(Stream stream)
        {
            
            var doc = new GcPdfDocument();
            var page = doc.NewPage();
            var g = page.Graphics;
            var tf = new TextFormat();
            tf.Font = StandardFonts.Helvetica;
            tf.FontSize = 14;

            var ip = new PointF(72, 72);
            float fldOffset = 72f * 3f;
            float fldHeight = tf.FontSize * 1.6f;
            float dY = 28;

            // Add sample fields:
            int orderindex = 1;
            var sampleGcPropTextFields = GetSampleGcPropTextFields();
            foreach (var data in sampleGcPropTextFields)
            {
                string fieldName = data.Key;

                g.DrawString($"{fieldName}:", tf, ip);

                var field = new TextField();
                // Fill GcProps dictionary:
                KeyValuePair<string, object>[] gcProps = data.Value;
                foreach(var gcProp in gcProps)
                {
                    field.GcProps[new PdfName(gcProp.Key)] = IPdfObjectExt.FromObject(gcProp.Value);
                }
                field.GcProps[new PdfName("orderindex")] = new PdfNumber(orderindex);
                field.Name = fieldName;
                field.Widget.Page = page;
                field.Widget.Rect = new RectangleF(ip.X + fldOffset, ip.Y, 72 * 3, fldHeight);
                field.Widget.DefaultAppearance.Font = tf.Font;
                field.Widget.DefaultAppearance.FontSize = tf.FontSize;
                doc.AcroForm.Fields.Add(field);
                ip.Y += dY;
                orderindex++;
            }

            // Done:
            doc.Save(stream);
        }

        // Used by SupportApiDemo to initialize GcPdfViewer.
        public static GcPdfViewerSupportApiDemo.Models.PdfViewerOptions PdfViewerOptions
        {
            get => new GcPdfViewerSupportApiDemo.Models.PdfViewerOptions(
                GcPdfViewerSupportApiDemo.Models.PdfViewerOptions.Options.SupportApi ,
                viewerTools: new string[] { "open", "save", "form-filler", "$navigation", "$split", "text-selection", "pan", "$zoom", "print", "rotate", "hide-annotations", "doc-properties", "about" });
        }

        public const string JS_CODE = @"
function createPdfViewer(selector, baseOptions) {
    var options = baseOptions || {};    
    options.formFiller = { title: 'Fill custom input Form Fields'}
    var viewer = new GcPdfViewer(selector, options);    
    viewer.addDefaultPanels();
    // Configure toolbar buttons:    
    viewer.toolbarLayout.viewer = { 
        default: ['open', 'save', 'form-filler', '$navigation', '$split', 'text-selection', 'pan', '$zoom', 'print', 'rotate', 'hide-annotations', 'doc-properties', 'about'], 
        mobile: ['open', 'save', 'form-filler', '$navigation', '$split', 'text-selection', 'pan', '$zoom', 'print', 'rotate', 'hide-annotations', 'doc-properties', 'about'], 
        fullscreen: ['$fullscreen', 'open', 'save', 'form-filler', '$navigation', '$split', 'text-selection', 'pan', '$zoom', 'print', 'rotate', 'hide-annotations', 'doc-properties', 'about']
    };
    viewer.applyToolbarLayout();
    viewer.applyOptions();
    return viewer;
}
";
    }
}