/*
 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.Collections.Generic;
using System.IO;
using System.Xml;
using Geometry;

namespace GestureSharpToolkit
{
    /// <summary>
    /// Implements I/O functions for gestures
    /// </summary>
    public class GestureIO
    {
        private static string m_folder = "";

        public static string Folder
        {
            get { return m_folder; }
            set
            {
                m_folder = value;
                if (!Directory.Exists(m_folder))
                    Directory.CreateDirectory(m_folder);
            }
        }

        /// <summary>
        /// Returns the full path on the disk for a given dataset specified by its name, e.g., "Vatavu2011Difficulty"
        /// </summary>
        private static string GetFullPathForDataset(string datasetName)
        {
            return String.Format("{0}\\{1}.xml", Folder, datasetName);
        }

        /// <summary>
        /// Reads all the gestures from the file filename
        /// </summary>
        public static List<Gesture> Read(string fileName)
        {
            List<Gesture> gestures = new List<Gesture>();

            if (!File.Exists(GetFullPathForDataset(fileName))) 
                return gestures;

            using (XmlTextReader xmlReader = new XmlTextReader(File.OpenText(GetFullPathForDataset(fileName))))
            {
                List<Point> points = null;
                int strokeId = -1;
                while (xmlReader.Read())
                {
                    switch (xmlReader.Name.ToUpper())
                    {
                        case "GESTURE":
                            switch (xmlReader.NodeType)
                            {
                                case XmlNodeType.Element: points = new List<Point>(); strokeId = -1; break;
                                case XmlNodeType.EndElement: gestures.Add(new Gesture(points.ToArray())); break;
                            }
                            break;
                        case "STROKE": 
                            if (xmlReader.NodeType == XmlNodeType.Element) strokeId++; 
                            break;
                        case "POINT":
                            points.Add(new Point(
                                double.Parse(xmlReader["X"]),
                                double.Parse(xmlReader["Y"]),
                                double.Parse(xmlReader["Z"]),
                                double.Parse(xmlReader["T"]),
                                strokeId
                            ));
                            break;
                    }
                }
            }
            return gestures;
        }

        /// <summary>
        /// Reads all the gestures of specified type from the specified participant
        /// </summary>
        public static List<Gesture> Read(DataSet set, string participant, string gestureType)
        {
            return Read(set, participant, new string[] { gestureType })[0];
        }

        /// <summary>
        /// Reads all the gestures of specified types from the specified participant and returns a list indexed by gesture x trial
        /// </summary>
        public static List<List<Gesture>> Read(DataSet set, string participant, string[] gestureTypes = null)
        {
            List<string> gestureTypesList = (gestureTypes == null) ? null : new List<string>(gestureTypes);

            List<List<Gesture>> list = new List<List<Gesture>>();
            for (int idxGestureType = 0; idxGestureType < set.Gestures.Length; idxGestureType++)
                if (gestureTypesList == null ||                               // read all the gesture types
                    gestureTypesList.Contains(set.Gestures[idxGestureType]))  // read selected gesture types
                {
                    List<Gesture> gestures = GestureIO.Read(set.Folder + "\\" + participant + "\\" + set.Gestures[idxGestureType]);
                    foreach (Gesture gesture in gestures)  
                        gesture.ClassId = idxGestureType; // useful for recognition experiments
                    list.Add(gestures);
                }
            return list;
        }

        /// <summary>
        /// Reads all the gestures of specified types from all the participants and returns a list indexed by participant x gesture x trial
        /// </summary>
        public static List<List<List<Gesture>>> Read(DataSet set, string[] gestureTypes = null, bool verbose = false)
        {
            List<List<List<Gesture>>> gestures = new List<List<List<Gesture>>>();
            foreach (string participant in set.Participants)
            {
                if (verbose) Console.WriteLine("Loading data from participant {0}: ... ", participant);
                gestures.Add(Read(set, participant, gestureTypes));
            }
            return gestures;
        }
    }
}
