﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using UnityEngine;

namespace Neuralyzer.Transport
{
  [Serializable]
  public class RoomStateGen
  {
    public Dictionary<string, string> props;
    public List<RoomObject> objects;

    public RoomStateGen(RoomStateGen oldStateGen = null)
    {
      if (oldStateGen == null)
      {
        props = new Dictionary<string, string>();
        objects = new List<RoomObject>();
        return;
      }
      props = new Dictionary<string, string>(oldStateGen.props);
      objects = new List<RoomObject>(oldStateGen.objects);
    }
  }

  [Serializable]
  public struct PropsOnlyState
  {
    public Dictionary<string, string> props;
    public object objects;
  }

  [Serializable]
  public class RoomObject
  {
    public string id;
    public Dictionary<string, object> props;
    public bool disposable;
    public string owner = "";

    public static bool operator ==(RoomObject r1, RoomObject r2)
    {
      if (Equals(r1, null))
      {
        return Equals(r2, null);
      }
      if (Equals(r2, null))
        return false;
      return r1.id == r2.id;
    }

    public static bool operator !=(RoomObject r1, RoomObject r2)
    {
      return !(r1 == r2);
    }

    public override bool Equals(object obj)
    {
      var o = obj as RoomObject;
      return o != null && o.id == id;
    }

    public override int GetHashCode()
    {
      return id.GetHashCode();
    }
  }

  [Serializable]
  public class StateUpdate
  {
    //reserved entries are create, update, and delete
    public Dictionary<string, string> props;
    public List<RoomObject> create;
    public List<RoomObject> update;
    public List<string> delete;

    public StateUpdate()
    {
      props = new Dictionary<string, string>();
      create = new List<RoomObject>();
      update = new List<RoomObject>();
      delete = new List<string>();
    }

    public void AddObject(RoomObject newObj)
    {
        create.Add(newObj);
    }

    public void RemoveObject(RoomObject remObj)
    {
        delete.Add(remObj.id);
    }

    public void UpdateObject(RoomObject updObj)
    {
      if (update.Any(o=>o.id == updObj.id))
      {
        update[update.IndexOf(updObj)] = updObj;
      }
      else
      {
        update.Add(updObj);
      }
    }

    public void UpdateProperty(string prop, bool value)
    {
      UpdateProperty(prop, value.ToString());
    }

    public void UpdateProperty(string prop, int value)
    {
      UpdateProperty(prop,value.ToString());
    }

    public void UpdateProperty(string prop, float value)
    {
      UpdateProperty(prop, value.ToString(CultureInfo.InvariantCulture));
    }

    public void UpdateProperty(string prop, string value)
    {
      if (props.ContainsKey(prop))
      {
        props[prop] = value;
      }
      else
      {
        props.Add(prop, value);
      }
    }
  }

  [Serializable]
  public struct ServerMessage
  {
    public string msgType;
    public object data;
  }

  [Serializable]
  public struct InitialState
  {
    public string name;
    public object[] participants;
    public object state;
    public string id;
  }

  [Serializable]
  public struct UserObject
  {
    public string name;
    public Vector3 pos;
    public Vector3 gaze;
    public string deviceType;
    public string id;
    public string sid;
  }

  [Serializable]
  public struct UserJLMessage
  {
    public string roomId;
    public object participant;
  }

  [Serializable]
  public struct RoomCreatedMessage
  {
    public string roomName;
    public string roomId;
  }

  public struct CreatedEventArgs
  {
    public string name;
  }

  public struct UserLeftEventArgs
  {
    public string username;
  }

  public struct UserJoinedEventArgs
  {
    public string username;
  }

  public struct PropertiesChangedEventArgs
  {
    public Dictionary<string, string> propsChanged;
  }

  public struct ErrorMessageEventArgs
  {
    public string message;
  }
}
