/*
 DatasetReader application (C#, .NET Framework)
 for the DATASET ID #MI-GESTURES-WGR-2022.

 	  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

 	  Ovidiu-Ciprian Ungurean, Ph.D.
      MintViz Lab, MANSiD Research Center
	  University Stefan cel Mare of Suceava
	  Suceava 720229, Romania
	  ungurean.ovidiu@gmail.com 

 The academic publication for this dataset, and what should be used to cite it, is:
 
	  Vatavu, R.-D. and Ungurean, O.-C. (2022).Understanding Gesture Input 
      Articulation with Upper-Body Wearables for Users with Upper-Body Motor Impairments. 
      In CHI Conference on Human Factors in Computing Systems (CHI '22), April 29-May 5, 2022,
      New Orleans, LA, USA. ACM, New York, NY, USA, 16 pages. 
	  https://doi.org/10.1145/3491102.3501964

 This software is distributed under the "New BSD License" agreement:

 Copyright (c) 2022, Radu-Daniel Vatavu and Ovidiu-Ciprian Ungurean. 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 OR 
 Ovidiu-Ciprian Ungurean 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.Collections.Generic;

namespace GestureSharpToolkit
{
    /// <summary>
    /// Implements a gesture dataset with the following folder structure on the disk:
    /// > DatasetName
    ///     > Participant (e.g., 101)
    ///         > gesture.ext (e.g., BackPoke.xml)
    ///         > gesture.ext (e.g., Circle.xml)
    ///         ...
    ///         > gesture.ext (e.g., Swipe-left.xml)
    /// </summary>
    public class DataSet
    {
        public string Folder;                 // the location of the dataset on the disk
        public string[] Participants;         // participants' names representing subfolders
        public string[] Gestures;             // gesture names
        public string Device;                 // details about the acquisition device

        private List<List<List<Gesture>>> m_samples;   // m_samples[i][j][k] is indexed by participant i, gesture type j, and trial k
        private int m_numSamples;                      // total number of gesture samples in this dataset

        #region constructor

        /// <summary>
        /// Creates a new gesture dataset
        /// </summary>
        public DataSet(string baseFolder, string[] participants, string[] gestures, string device = "")
        {
            this.Folder = baseFolder;
            this.Participants = participants;
            this.Gestures = gestures;
            this.Device = device;
            this.m_samples = null;
            this.m_numSamples = 0;
        }

        #endregion

        #region read gestures

        /// <summary>
        /// Read gestures from the disk
        /// </summary>
        public void ReadGestures(bool verbose = false, string[] gestureTypes = null)
        {
            if (verbose) Console.WriteLine("Loading gesture dataset {0}:", Folder);

            // read gestures from the disk (all participants x all gesture types)
            this.m_samples = GestureIO.Read(this, gestureTypes, verbose);
            CountSamples();

            if (verbose) Console.WriteLine("{0} gestures loaded.", Size);
        }

        /// <summary>
        /// Counts the total number of gesture samples in this dataset
        /// </summary>
        private void CountSamples()
        {
            this.m_numSamples = 0;
            for (int idxPart = 0; idxPart < m_samples.Count; idxPart++)
                for (int idxGesture = 0; idxGesture < m_samples[idxPart].Count; idxGesture++)
                    this.m_numSamples += m_samples[idxPart][idxGesture].Count;
        }

        #endregion

        #region properties

        public int Size
        {
            get { return m_numSamples; }
        }

        public List<List<List<Gesture>>> GetGestures()
        {
            return m_samples;
        }

        public List<Gesture> GetGestures(int idxParticipant, int idxGesture)
        {
            return m_samples?[idxParticipant][idxGesture];
        }

        public Gesture[] GetGesturesArray()
        {
            return m_samples?.SelectMany(x => x.ToArray()).SelectMany(x => x.ToArray()).ToArray();
        }

        public Gesture[] GetGesturesArray(int idxParticipant)
        {
            return m_samples?[idxParticipant].SelectMany(x => x.ToArray()).ToArray();
        }

        #endregion

        /// <summary>
        /// Stroke gestures collected with a Samsung Gear Fit 2 used as a watch, ring, and touchpad on the
        /// right temple of a pair of glasses. Participants with and without motor impairments.
        /// </summary>
        public static class Watch_Glasses_Ring_2022
        {
            private static string m_folderName = "";
            private static string[] m_strokeGestures = new string[] {
               "asterisk", "check mark", "circle", "heart", "letter A", "letter M", "letter X",
               "six-point star", "square", "swipe left", "swipe right", "zigzag"
            };
            private static string[] m_motionGesturesRing = new string[] { "circle", "double tap", "pinch thumb", "scratch surface", "slide thumb", "tap" };
            private static string[] m_motionGesturesWatch = new string[] { "circle", "double tap", "rotate fast and slow", "shake", "rotate slow and fast", "tap" };
            private static string[] m_motionGesturesGlasses = new string[] { "circle", "double tap", "lean in front", "lean to left shoulder", "rotate left", "tap" };
            private static string m_device = "Samsung Gear Fit 2";

            // touchscreen stroke-gestures with the thumb on the ring worn on the index finger
            public static DataSet MotorImpairments_StrokeGestures_Ring = new DataSet(
                m_folderName + "\\StrokeGestures_Ring",
                new string[] { "102", "103", "104", "105", "106", "107", "109", "110", "111", "112", "113" },
                m_strokeGestures, m_device
            );
            public static DataSet NoImpairments_StrokeGestures_Ring = new DataSet(
                m_folderName + "\\StrokeGestures_Ring",
                new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14" },
                m_strokeGestures, m_device
            );

            // touchscreen stroke-gestures on smartwatch
            public static DataSet MotorImpairments_StrokeGestures_Watch = new DataSet(
                m_folderName + "\\StrokeGestures_Watch",
                new string[] { "101", "102", "103", "104", "105", "107", "108", "110", "111", "112", "113", "114" },
                m_strokeGestures, m_device
            );
            public static DataSet NoImpairments_StrokeGestures_Watch = new DataSet(
                m_folderName + "\\StrokeGestures_Watch",
                new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14" },
                m_strokeGestures, m_device
            );

            // touchscreen stroke-gestures on glasses temple
            public static DataSet MotorImpairments_StrokeGestures_Glasses = new DataSet(
               m_folderName + "\\StrokeGestures_Glasses",
               new string[] { "101", "102", "103", "104", "105", "106", "110", "111", "112", "113", "114" },
               m_strokeGestures, m_device
            );
            public static DataSet NoImpairments_StrokeGestures_Glasses = new DataSet(
              m_folderName + "\\StrokeGestures_Glasses",
              new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14" },
              m_strokeGestures, m_device
            );

            // motion gestures with the index finger
            public static DataSet MotorImpairments_MotionGestures_Ring = new DataSet(
                m_folderName + "\\MotionGestures_Ring",
                new string[] { "102", "103", "104", "105", "106", "107", "109", "110", "111", "112", "113", "114" },
                m_motionGesturesRing, m_device
            );
            public static DataSet NoImpairments_MotionGestures_Ring = new DataSet(
                m_folderName + "\\MotionGestures_Ring",
                new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14" },
                m_motionGesturesRing, m_device
            );

            // motion gestures with the hand and wrist
            public static DataSet MotorImpairments_MotionGestures_Watch = new DataSet(
                m_folderName + "\\MotionGestures_Watch",
                new string[] { "101", "103", "104", "105", "107", "108", "109", "110", "111", "112", "113", "114" },
                m_motionGesturesWatch, m_device
            );
            public static DataSet NoImpairments_MotionGestures_Watch = new DataSet(
                m_folderName + "\\MotionGestures_Watch",
                new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14" },
                m_motionGesturesWatch, m_device
            );

            // motion gestures with the head
            public static DataSet MotorImpairments_MotionGestures_Glasses = new DataSet(
                m_folderName + "\\MotionGestures_Glasses",
                new string[] { "101", "102", "103", "104", "105", "106", "107", "108", "109", "110", "111", "112", "113", "114" },
                m_motionGesturesGlasses, m_device
            );
            public static DataSet NoImpairments_MotionGestures_Glasses = new DataSet(
                m_folderName + "\\MotionGestures_Glasses",
                new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14" },
                m_motionGesturesGlasses, m_device
            );
        }
    }
}