using System;
using System.Collections.Generic;
using System.Diagnostics;
using Autodesk.Revit;
using Autodesk.Revit.Elements;
using CylindricalFace = Autodesk.Revit.Geometry.CylindricalFace;
using Edge = Autodesk.Revit.Geometry.Edge;
using PlanarFace = Autodesk.Revit.Geometry.PlanarFace;
using Transform = Autodesk.Revit.Geometry.Transform;
using XYZ = Autodesk.Revit.Geometry.XYZ;

namespace CH_Revit
{
  class Util
  {
    #region Geometrical Comparison
    const double _eps = 1.0e-9;

    static public bool IsZero(double a)
    {
      return _eps > Math.Abs(a);
    }

    static public bool IsHorizontal(XYZ v)
    {
      return IsZero(v.Z);
    }

    static public bool IsVertical(XYZ v)
    {
      return IsZero(v.X) && IsZero(v.Y);
    }

    static public bool IsHorizontal(Edge e)
    {
      XYZ p = e.Evaluate(0);
      XYZ q = e.Evaluate(1);

      return IsHorizontal(q - p);
    }

    static public bool IsHorizontal(PlanarFace f)
    {
      return IsVertical(f.Normal);
    }

    static public bool IsVertical(PlanarFace f)
    {
      return IsHorizontal(f.Normal);
    }

    static public bool IsVertical(CylindricalFace f)
    {
      return IsVertical(f.Axis);
    }
    #endregion

    #region Unit Handling
    const double _convertFootToMm = 12 * 25.4;

    static public double FootToMm(double length)
    {
      return length * _convertFootToMm;
    }
    #endregion

    #region Formatting
    // Return an English plural suffix 's' or nothing for the given number of items.
    public static string PluralSuffix(int n)
    {
      return n == 1 ? "" : "s";
    }

    public static string DotOrColon(int n)
    {
      return n > 1 ? ":" : ".";
    }

    static public string RealString(double a)
    {
      return a.ToString("0.##");
    }

    static public string AngleString(double angle)
    {
      return RealString(angle * 180 / Math.PI) + " degrees";
    }

    static public string MmString(double length)
    {
      return RealString(FootToMm(length)) + " mm";
    }

    static public string PointString(XYZ p)
    {
      return string.Format("({0},{1},{2})", RealString(p.X), RealString(p.Y), RealString(p.Z));
    }

    static public string TransformString(Transform t)
    {
      return string.Format("({0},{1},{2},{3})", PointString(t.Origin), PointString(t.BasisX), PointString(t.BasisY), PointString(t.BasisZ));
    }
    #endregion

    const string _caption = "Cedarglen Homes Revit Application";

    static public void InfoMsg(string msg)
    {
      Debug.WriteLine(msg);
      System.Windows.Forms.MessageBox.Show(msg, _caption, System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information);
    }

    public static string ElementDescription(Element e)
    {
      // for a wall, the element name equals the wall type name, which is equivalent to the family name ...
      FamilyInstance fi = e as FamilyInstance;

      string fn = (null == fi) ? string.Empty : fi.Symbol.Family.Name + " ";

      string cn = (null == e.Category) ? e.GetType().Name : e.Category.Name;

      return string.Format("{0} {1}<{2} {3}>", cn, fn, e.Id.Value, e.Name);
    }

    #region Element Selection
    public static Element SelectSingleElement(Document doc, string description)
    {
      Selection sel = doc.Selection;
      Element e = null;
      sel.Elements.Clear();
      sel.StatusbarTip = "please select " + description;
      if(sel.PickOne())
      {
        ElementSetIterator elemSetItr = sel.Elements.ForwardIterator();
        elemSetItr.MoveNext();
        e = elemSetItr.Current as Element;
      }
      return e;
    }

    public static bool GetSelectedElementsOrAll(
      List<Element> a, // return value container
      Document doc,
      Type t)
    {
      Selection sel = doc.Selection;
      if (sel.Elements.Size > 0)
      {
          foreach (Element e in sel.Elements)
              if (t.IsInstanceOfType(e))
                  a.Add(e);
      }
      else
          doc.get_Elements(t, a);

      return a.Count > 0;
    }
    #endregion
  }
}
