/**
 * DatasetReader application (C#, .NET Framework 4.6.1)
 * for the visual impairments stroke-gesture dataset.
 *
 * 	    Radu-Daniel Vatavu, Ph.D.
 *      MintViz Lab, MANSiD Research Center
 *	    University Stefan cel Mare of Suceava
 *	    Suceava 720229, Romania
 *	    radu.vatavu@usm.ro
 *      http://www.eed.usv.ro/~vatavu
 *
 * The academic publication for this dataset, and what should be used to cite it, is:
 *
 *	  Radu-Daniel Vatavu, Bogdan-Florin Gheran, Maria-Doina Schipor. (2018).
 *	  The Impact of Low Vision on Touch-Gesture Articulation on Mobile Devices.
 *    IEEE Pervasive Computing 17(1). IEEE, 27-37
 *    https://doi.org/10.1109/MPRV.2018.011591059
 *
 * This software is distributed under the "New BSD License" agreement:
 *
 * Copyright (c) 2018, Radu-Daniel Vatavu. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    * Neither the name of the University Stefan cel Mare of Suceava, nor 
 *      the names of its contributors may be used to endorse or promote products 
 *      derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Radu-Daniel Vatavu BE LIABLE FOR 
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**/

using System;
using System.Linq;
using System.IO;
using System.Collections.Generic;

namespace DatasetReader
{
    static class Program
    {
        #region dataset description

        static string datasetFolder = "Dataset";

        static string[] gestureTypes = new string[]
        {
        //    "down", "up", "left", "right",
            "letter_A", "arrow_right", "circle", "letter_M",
            "stick_figure", "question_mark", "letter_R", "letter_S",
            "sol_key", "spiral", "square", "star" 
        };

        const int MAX_NUMBER_OF_SAMPLES_PER_GESTURE_TYPE = 10;

        private static bool IsSymbolicGesture(string gestureType)
        {
            return (gestureType != "down" && 
                    gestureType != "up" && 
                    gestureType != "left" && 
                    gestureType != "right");
        }

        struct Participant
        {
            public string ID;
            public bool VisualImpairment;
            public double Age;
            public char Gender;
            public string Description;
        };

        static Participant[] participants = new Participant[]
        {
            // participants with visual impairments (27)
            new Participant(){ID = "101_VI", Gender = 'F', Age = 21.6, VisualImpairment = true, Description = "astigmatism, congenital nystagmus, strabismus, high myopia (OD= −9.00D, OS= −9.00D)"},
            new Participant(){ID = "102_VI", Gender = 'M', Age = 19.1, VisualImpairment = true, Description = "chorioretinal degeneration, cataract, moderate to high myopia (OD= −6.00D, OS=−6.25D)"},
            new Participant(){ID = "104_VI", Gender = 'F', Age = 62.0, VisualImpairment = true, Description = "congenital nystagmus, amblyopia, moderate myopia (OD= −4.00D, OS=−4.25D)"},
            new Participant(){ID = "105_VI", Gender = 'M', Age = 52.1, VisualImpairment = true, Description = "congenital nystagmus, high myopia (OD= −16.00D, OS= −18.00D)"},
            new Participant(){ID = "106_VI", Gender = 'M', Age = 49.2, VisualImpairment = true, Description = "congenital nystagmus, high myopia (OD= −12.50D, OS= −13.00D)"},
            new Participant(){ID = "107_VI", Gender = 'M', Age = 23.9, VisualImpairment = true, Description = "congenital nystagmus, macular displasya, microphthalmus, moderate myopia (OD= −4.00D, OS= −4.50D)"},
            new Participant(){ID = "108_VI", Gender = 'F', Age = 53.4, VisualImpairment = true, Description = "macular degeneration, optic nerve atrophy, moderate hyperopia (OD= +4.00D, OS= +4.50D)"},
            new Participant(){ID = "109_VI", Gender = 'M', Age = 31.1, VisualImpairment = true, Description = "astigmatism, congenital nystagmus, high myopia (OD= −16.00D, OS=−16.25D)"},
            new Participant(){ID = "110_VI", Gender = 'F', Age = 33.5, VisualImpairment = true, Description = "congenital nystagmus, high hyperopia (OD=+6.00D, OS= +6.25D)"},
            new Participant(){ID = "111_VI", Gender = 'F', Age = 33.5, VisualImpairment = true, Description = "chorioretinal degeneration, moderate hyperopia (OD= +3.50, OS= +4.00D)"},
            new Participant(){ID = "113_VI", Gender = 'M', Age = 29.8, VisualImpairment = true, Description = "astigmatism, congenital nystagmus, high myopia (OD= −8.00D, OS=−8.50D)"},
            new Participant(){ID = "114_VI", Gender = 'M', Age = 36.3, VisualImpairment = true, Description = "severe amblyopia (OD= −6.00D, OS= −6.75D)"},
            new Participant(){ID = "116_VI", Gender = 'F', Age = 43.7, VisualImpairment = true, Description = "congenital nystagmus, high myopia (OD= −11.00D, OS= −11.25D)"},
            new Participant(){ID = "117_VI", Gender = 'F', Age = 46.8, VisualImpairment = true, Description = "degenerative high myopia (OD= −10.00D, OS= −11.00D), strabismus, macular choroiditis"},
            new Participant(){ID = "118_VI", Gender = 'F', Age = 29.2, VisualImpairment = true, Description = "high myopia (OD=−6.25D, OS= −6.25D)"},
            new Participant(){ID = "120_VI", Gender = 'M', Age = 32.4, VisualImpairment = true, Description = "astigmatism, chorioretinal degeneration, high myopia (OD= −16.00D, OS=−14.00D)"},
            new Participant(){ID = "122_VI", Gender = 'F', Age = 21.8, VisualImpairment = true, Description = "moderate myopia (OD= −4.37, OS= −5.87)"},
            new Participant(){ID = "201_VI", Gender = 'F', Age = 18.4, VisualImpairment = true, Description = "late congenital glaucoma (OD VA= 0.02, OS VA= 0.02)"},
            new Participant(){ID = "202_VI", Gender = 'F', Age = 18.8, VisualImpairment = true, Description = "severe amblyopia (VA= 0.002), persistence of Cloquet’s canal, persistent pupillary membrane, congenital ocular toxoplasmosis, compound myopic astigmatism"},
            new Participant(){ID = "203_VI", Gender = 'M', Age = 17.8, VisualImpairment = true, Description = "optic nerve hypoplasia, congenital nystagmus, amblyopia (severe), sensory exotropia, ocular herpes (VA= 0.08)"},
            new Participant(){ID = "204_VI", Gender = 'F', Age = 18.6, VisualImpairment = true, Description = "severe amblyopia (OD VA= 0.08, OS VA= 0.02)"},
            new Participant(){ID = "205_VI", Gender = 'M', Age = 16.8, VisualImpairment = true, Description = "severe hypermetropia with astigmatism, amblyopia, anisometropia, congenital nystagmus (VA= 0.15)"},
            new Participant(){ID = "206_VI", Gender = 'F', Age = 16.5, VisualImpairment = true, Description = "congenital nystagmus, glaucoma (with surgery), pseudophakia, amblyopia (VA= 0.10)"},
            new Participant(){ID = "207_VI", Gender = 'F', Age = 15.9, VisualImpairment = true, Description = "retinopathy of prematurity (OS distinguishes hand motion, OD perception at 10 cm)"},
            new Participant(){ID = "208_VI", Gender = 'M', Age = 16.2, VisualImpairment = true, Description = "sequelae of retinopathy of prematurit, total retinal detachment, aniridia, congenital cataract, amblyopia (severe), fixation nystagmus (OD: no light perception, OS VA= 0.2)"},
            new Participant(){ID = "209_VI", Gender = 'M', Age = 14.5, VisualImpairment = true, Description = "hypermetropic astigmatism, severe amblyopia, paralytic strabismus (OD VA=0.033, OS VA= 0.033)"},
            new Participant(){ID = "210_VI", Gender = 'F', Age = 15.3, VisualImpairment = true, Description = "hypermetropic astigmatism, severe amblyopia, paralytic strabismus (OD VA=0.033, OS VA= 0.033)"},

            // participants without visual impairments (27)
            new Participant(){ID = "001", Gender = 'F', Age = 22.1, VisualImpairment = false, Description = ""},
            new Participant(){ID = "002", Gender = 'F', Age = 22.0, VisualImpairment = false, Description = ""},
            new Participant(){ID = "003", Gender = 'F', Age = 21.4, VisualImpairment = false, Description = ""},
            new Participant(){ID = "004", Gender = 'F', Age = 21.4, VisualImpairment = false, Description = ""},
            new Participant(){ID = "005", Gender = 'F', Age = 19.8, VisualImpairment = false, Description = ""},
            new Participant(){ID = "006", Gender = 'M', Age = 25.1, VisualImpairment = false, Description = ""},
            new Participant(){ID = "007", Gender = 'F', Age = 18.5, VisualImpairment = false, Description = ""},
            new Participant(){ID = "008", Gender = 'M', Age = 19.9, VisualImpairment = false, Description = ""},
            new Participant(){ID = "009", Gender = 'F', Age = 20.0, VisualImpairment = false, Description = ""},
            new Participant(){ID = "010", Gender = 'M', Age = 20.0, VisualImpairment = false, Description = ""},
            new Participant(){ID = "011", Gender = 'M', Age = 19.7, VisualImpairment = false, Description = ""},
            new Participant(){ID = "012", Gender = 'F', Age = 43.0, VisualImpairment = false, Description = ""},
            new Participant(){ID = "013", Gender = 'M', Age = 41.9, VisualImpairment = false, Description = ""},
            new Participant(){ID = "014", Gender = 'F', Age = 39.7, VisualImpairment = false, Description = ""},
            new Participant(){ID = "015", Gender = 'M', Age = 40.8, VisualImpairment = false, Description = ""},
            new Participant(){ID = "016", Gender = 'M', Age = 40.0, VisualImpairment = false, Description = ""},
            new Participant(){ID = "017", Gender = 'M', Age = 36.3, VisualImpairment = false, Description = ""},
            new Participant(){ID = "018", Gender = 'F', Age = 47.5, VisualImpairment = false, Description = ""},
            new Participant(){ID = "021", Gender = 'M', Age = 50.6, VisualImpairment = false, Description = ""},
            new Participant(){ID = "115", Gender = 'F', Age = 19.7, VisualImpairment = false, Description = ""},
            new Participant(){ID = "119", Gender = 'F', Age = 41.2, VisualImpairment = false, Description = ""},
            new Participant(){ID = "123", Gender = 'F', Age = 22.9, VisualImpairment = false, Description = ""},
            new Participant(){ID = "301", Gender = 'F', Age = 21.6, VisualImpairment = false, Description = ""},
            new Participant(){ID = "302", Gender = 'F', Age = 21.9, VisualImpairment = false, Description = ""},
            new Participant(){ID = "303", Gender = 'M', Age = 22.8, VisualImpairment = false, Description = ""},
            new Participant(){ID = "304", Gender = 'M', Age = 21.3, VisualImpairment = false, Description = ""},
            new Participant(){ID = "305", Gender = 'F', Age = 39.2, VisualImpairment = false, Description = ""},
        };

        #endregion

        #region main function: reads the dataset

        [STAThread]
        static void Main()
        {
            // print a summary of the dataset
            Console.WriteLine("=====================================");
            Console.WriteLine("Dataset summary");
            Console.WriteLine("=====================================");
            Console.Write("Number of participants: {0}, ", participants.Length);
            Console.WriteLine("of which {0} participants with visual impairments", participants.Where(p => p.VisualImpairment).Count());
            Console.WriteLine("Gender: {0} males and {1} females", participants.Where(p => p.Gender == 'M').Count(), participants.Where(p => p.Gender == 'F').Count());
            Console.WriteLine(
                "Mean age {0:.0} years for participants with visual impairments and {1:.0} years for participants without visual impairments.",
                participants.Where(p => p.VisualImpairment).Average(p => p.Age),
                participants.Where(p => !p.VisualImpairment).Average(p => p.Age)
            );
            Console.WriteLine();

            // read the gestures
            int[] numSamples = new int[] { 0, 0 };
            foreach (Participant participant in participants)
            {
                Console.Write("reading data for p.ID# {0,-4} ...", participant.ID);

                List<Gesture[]> gestures = new List<Gesture[]>();
                foreach (string gestureType in gestureTypes)
                {
                    string fileName = String.Format("{0}\\{1}\\{2}.xml", datasetFolder, participant.ID, gestureType);
                    if (File.Exists(fileName))
                    {
                        string gestureName = Path.GetFileNameWithoutExtension(fileName);
                        if (IsSymbolicGesture(gestureName))
                        {
                            Gesture[] samples = GestureIO.Read(fileName);
                            gestures.Add(samples);
                            numSamples[participant.VisualImpairment ? 0 : 1] += samples.Length;
                        }
                    }
                }

                int n = gestures.Sum(g => g.Length);
                Console.WriteLine(" {0,3} samples (completion rate: {1:.0}%)", n, n * 100.0 / MAX_NUMBER_OF_SAMPLES_PER_GESTURE_TYPE / gestureTypes.Length);
            }

            Console.WriteLine();
            Console.WriteLine(
                "Total: {0} gesture samples, of which {1} from participants with visual impairments.", 
                numSamples[0] + numSamples[1], numSamples[0]
            );
            Console.WriteLine();
            Console.Read();
        }

        #endregion
    }
}