internal FieldActualInfo(Page page, Template.Field actualfield, RectangleF?actualRectangle, FieldActualInfo tableFieldActualInfo)
 {
     this.page            = page;
     ActualField          = actualfield;
     ActualRectangle      = actualRectangle;
     TableFieldActualInfo = tableFieldActualInfo;
     Found             = ActualRectangle != null;
     types2cachedValue = new HandyDictionary <Template.Field.Types, object>(
         disposeValue: (object v) =>
     {
         if (v == null)
         {
             return;
         }
         if (v is Bitmap)
         {
             ((Bitmap)v).Dispose();
         }
         else if (v is List <Bitmap> )
         {
             foreach (Bitmap b in (List <Bitmap>)v)
             {
                 b?.Dispose();
             }
         }
     }
         );
 }
 List <FieldActualInfo> getFieldActualInfos(string fieldName)
 {
     if (!fieldNames2fieldActualInfos.TryGetValue(fieldName, out List <FieldActualInfo> fais))
     {
         fais = new List <FieldActualInfo>();
         fieldNames2fieldActualInfos[fieldName] = fais;
         if (PageCollection.ActiveTemplate == null)
         {
             throw new Exception("ActiveTemplate is not set for the PageCollection.");
         }
         foreach (Template.Field f in PageCollection.ActiveTemplate.Fields.Where(x => x.Name == fieldName))
         {
             RectangleF?     ar  = getFieldActualRectangle(f);
             FieldActualInfo fai = new FieldActualInfo(this, f, ar, f.ColumnOfTable != null ? getFoundFieldActualInfo(f.ColumnOfTable) : null);
             if (fai.Found)
             {
                 fais.Insert(0, fai);
                 break;
             }
             fais.Add(fai);
         }
         if (fais.Count < 1)
         {
             throw new Exception("Field[name=" + fieldName + "] does not exist.");
         }
     }
     return(fais);
 }
 internal FieldActualInfo(Page page, Template.Field actualfield, RectangleF?actualRectangle, FieldActualInfo tableFieldActualInfo)
 {
     this.page            = page;
     ActualField          = actualfield;
     ActualRectangle      = actualRectangle;
     TableFieldActualInfo = tableFieldActualInfo;
 }
        public List <Bitmap> GetOcrTextLineImages(string fieldName)
        {
            FieldActualInfo fai = getFoundFieldActualInfo(fieldName);

            if (!fai.Found)
            {
                return(null);
            }
            return((List <Bitmap>)fai.GetValue(Template.Field.Types.OcrTextLineImages));
        }
        public Bitmap GetImage(string fieldName)
        {
            FieldActualInfo fai = getFoundFieldActualInfo(fieldName);

            if (!fai.Found)
            {
                return(null);
            }
            return((Bitmap)fai.GetValue(Template.Field.Types.Image));
        }
        public object GetValue(string fieldName, Template.Field.ValueTypes?valueType = null)
        {
            FieldActualInfo fai = getFieldActualInfo(fieldName, true);

            if (!fai.Found)
            {
                return(null);
            }
            return(fai.GetValue(valueType == null ? fai.ActualField.DefaultValueType : (Template.Field.ValueTypes)valueType));
        }
        /// <summary>
        /// Tries field definitions of the given name in turn until some is found on the page.
        /// </summary>
        /// <param name="fieldName">field is referenced by name because there may be several field-definitions for the same name</param>
        /// <param name="actualField">actual field definition which was found on the page</param>
        /// <param name="type">if not set then DefaultValueType is used</param>
        /// <returns></returns>
        public object GetValue(string fieldName, out Template.Field actualField, Template.Field.Types?type = null)
        {
            FieldActualInfo fai = getFoundFieldActualInfo(fieldName);

            if (!fai.Found)
            {
                actualField = null;
                return(null);
            }
            actualField = fai.ActualField;
            return(fai.GetValue(type == null ? fai.ActualField.Type : (Template.Field.Types)type));
        }
        ///// <summary>
        ///// !!!passing Template.Field would be deceitful for 2 reasons:
        ///// - it may belong to another template than ActiveTemplate;
        ///// - it implies that a Template.Field object is equivalent to a field while it is just one of its defintions;
        ///// </summary>
        ///// <param name="field"></param>
        ///// <returns></returns>
        //public object GetValue(Template.Field exactField, Template.Field.ValueTypes? valueType = null)
        //{
        //    RectangleF? ar = getFieldActualRectangle(exactField);
        //    FieldActualInfo fai = new FieldActualInfo(this, exactField, ar, exactField.ColumnOfTable != null ? getFoundFieldActualInfo(exactField.ColumnOfTable) : null);
        //    if (!fai.Found)
        //        return null;
        //    return fai.GetValue(valueType == null ? fai.ActualField.DefaultValueType : (Template.Field.ValueTypes)valueType);
        //}

        internal FieldActualInfo GetFieldActualInfo(Template.Field field)
        {
            List <FieldActualInfo> fais = getFieldActualInfos(field.Name);
            FieldActualInfo        fai  = fais.Find(a => a.ActualField == field);

            if (fai == null)
            {
                RectangleF?ar = getFieldActualRectangle(field);
                fai = new FieldActualInfo(this, field, ar, field.ColumnOfTable != null ? getFoundFieldActualInfo(field.ColumnOfTable) : null);
                fais.Add(fai);
            }
            return(fai);
        }
        public List <CharBox> GetCharBoxes(string fieldName)
        {
            FieldActualInfo fai = getFoundFieldActualInfo(fieldName);

            if (!fai.Found)
            {
                return(null);
            }
            if (fai.ActualField is Template.Field.Pdf)
            {
                return((List <CharBox>)fai.GetValue(Template.Field.Types.PdfCharBoxs));
            }
            return((List <CharBox>)fai.GetValue(Template.Field.Types.OcrCharBoxs));
        }
        public List <string> GetTextLines(string fieldName)
        {
            FieldActualInfo fai = getFoundFieldActualInfo(fieldName);

            if (!fai.Found)
            {
                return(null);
            }
            if (fai.ActualField is Template.Field.Pdf)
            {
                return((List <string>)fai.GetValue(Template.Field.Types.PdfTextLines));
            }
            return((List <string>)fai.GetValue(Template.Field.Types.OcrTextLines));
        }
        /// <summary>
        /// It is helpful when a field has more than 1 definition and its image is required.
        /// !!!Only must be used for the field returned by GetValue(string fieldName, out Template.Field actualField, Template.Field.Types? type = null)
        /// ATTENTION: using Template.Field as a parameter may be deceitful for these reasons:
        /// - it may belong to another template than ActiveTemplate;
        /// - it implies that a Template.Field object is equivalent to a field while it is just one of its defintions;
        /// - it may be the same by logic while being another as an object;
        /// </summary>
        /// <param name="exactField"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        //public Bitmap GetImage(Template.Field exactField)
        //{
        //    RectangleF? ar = getFieldActualRectangle(exactField);
        //    FieldActualInfo fai = new FieldActualInfo(this, exactField, ar, exactField.ColumnOfTable != null ? getFoundFieldActualInfo(exactField.ColumnOfTable) : null);
        //    if (!fai.Found)
        //        return null;
        //    return (Bitmap)fai.GetValue(Template.Field.Types.Image);
        //}

        internal FieldActualInfo GetFieldActualInfo(Template.Field field)
        {
            List <FieldActualInfo> fais = getFieldActualInfos(field.Name);
            //FieldActualInfo fai = fais.Find(a => a.ActualField == field);!!!while the fields can be same by logic, they are different objects!
            string          fs  = Serialization.Json.Serialize(field, false, true);
            FieldActualInfo fai = fais.Find(a => Serialization.Json.Serialize(a.ActualField, false, true) == fs);

            if (fai == null)
            {
                RectangleF?ar = getFieldActualRectangle(field);
                fai = new FieldActualInfo(this, field, ar, field.ColumnOfTable != null ? getFoundFieldActualInfo(field.ColumnOfTable) : null);
                fais.Add(fai);
            }
            return(fai);
        }
 FieldActualInfo getFoundFieldActualInfo(string fieldName)
 {
     if (!fieldNames2fieldActualInfo.TryGetValue(fieldName, out FieldActualInfo fai))
     {
         RectangleF?    ar = null;
         Template.Field af = null;
         foreach (Template.Field f in PageCollection.ActiveTemplate.Fields.Where(x => x.Name == fieldName))
         {
             ar = getFieldActualRectangle(f);
             af = f;
             if (ar != null)
             {
                 break;
             }
         }
         if (af == null)
         {
             throw new Exception("Field[name=" + fieldName + "] does not exist.");
         }
         fai = new FieldActualInfo(this, af, ar, af.ColumnOfTable != null ? getFoundFieldActualInfo(af.ColumnOfTable) : null);
         fieldNames2fieldActualInfo[fieldName] = fai;
     }
     return(fai);
 }