/*
 DatasetReader application (C#, .NET Framework)
 for the DATASET ID# 2023-GESTURES-IFAD.

 	  Radu-Daniel Vatavu, Ph.D.
      MintViz Lab, MANSiD Research Center
      Stefan cel Mare University of Suceava
      Suceava 720229, Romania
      radu.vatavu @usm.ro
      http://www.eed.usv.ro/~vatavu

 The academic publication for this work, and what should be used to cite it, is:
 
    Radu-Daniel Vatavu. (2023). iFAD Gestures: Understanding Users' Gesture Input 
    Performance with Index-Finger Augmentation Devices. In Proceedings of the 
    2023 CHI Conference on Human Factors in Computing Systems (CHI '23). 
    ACM, New York, NY, USA, 17 pages. https://doi.org/10.1145/3544548.3580928

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

 Copyright (c) 2023, 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 Stefan cel Mare University 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.Collections.Generic;

namespace GestureSharpToolkit
{
    /// <summary>
    /// Implements a gesture dataset with the following folder structure:
    /// > 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>
        /// Motion gestures collected with a custom-made, index-finger worn 
        /// finger-augmentation device (FAD) with a built-in accelerometer.
        /// </summary>
        public static class iFAD_Gestures
        {
            private static readonly string m_folderName = "iFAD";
            private static readonly string m_device = "Custom-made iFAD";

            // motion gestures performed at finger level
            public static DataSet FingerLevel_Gestures = new DataSet(
                m_folderName,
                new string[] { "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", "110", "111", "112", "113", "114", "115", "116", "117", "118", "119" },
                new string[] { "Tap", "Double tap", "Back tap", "Double back tap", "Twist left", "Twist right", "Twist left-right", "Twist right-left", "Pull", "Pull twice" }, 
                m_device
            );

            // motion gestures performed at hand level
            public static DataSet HandLevel_Gestures = new DataSet(
                m_folderName,
                new string[] { "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", "110", "111", "112", "113", "114", "115", "116", "117", "118", "119" },
                new string[] { "Pinch", "Pinch twice", "Fist", "Vertical palm", "Horizontal palm", "Lateral palm", "Shake", "Shake twice", "Knob left", "Knob right" }, 
                m_device
            );

            // motion gestures performed at arm level
            public static DataSet ArmLevel_Gestures = new DataSet(
                m_folderName,
                new string[] { "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", "110", "111", "112", "113", "114", "115", "116", "117", "118", "119" },
                new string[] { "Circle", "Square", "Heart", "Letter X", "Letter M", "Letter S", "Check", "Question mark", "Swipe left", "Swipe right" }, 
                m_device
            );

            // body-referenced motion gestures
            public static DataSet BodyReferenced_Gestures = new DataSet(
                m_folderName,
                new string[] { "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", "110", "111", "112", "113", "114", "115", "116", "117", "118", "119" },
                new string[] { "Left ear", "Right ear", "Mouth", "Elbow", "Back neck", "Trousers front pocket", "Shirt pocket left", "Shirt pocket right", "Trousers back pocket", "Join hands" }, 
                m_device
            );
        }
    }
}