Subset network evaluators
SubsetNetworkEvaluatorsUI\SubsetHelperUI.cs
// Copyright 2012 ESRI
// 
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
// 
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
// 
// See the use restrictions.
// 

using System;
using System.Drawing;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using ESRI.ArcGIS.ADF.BaseClasses;
using ESRI.ArcGIS.ADF.CATIDs;
using ESRI.ArcGIS.Framework;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.NetworkAnalyst;
using ESRI.ArcGIS.ArcMapUI;
using ESRI.ArcGIS.NetworkAnalystUI;
using SubsetNetworkEvaluators;

namespace SubsetNetworkEvaluatorsUI
{
  /// <summary>
  /// The SubsetHelperUI is a utility class to aid in determining the relevant set of parameters
  /// to auto-update when set to listen to the events and other shared utilities.
  /// </summary>  
  class SubsetHelperUI
  {
    public static void PushParameterValuesToNetwork(INetworkAnalystExtension nax)
    {
      try
      {
        if (nax == null)
          return;

        bool naxEnabled = false;
        IExtensionConfig naxConfig = nax as IExtensionConfig;
        naxEnabled = naxConfig.State == esriExtensionState.esriESEnabled;

        if (!naxEnabled)
          return;

        INAWindow naWindow = nax.NAWindow;
        INALayer naLayer = null;
        INAContext naContext = null;
        INetworkDataset nds = null;

        naLayer = naWindow.ActiveAnalysis;
        if (naLayer != null)
          naContext = naLayer.Context;

        if (naContext != null)
          nds = naContext.NetworkDataset;

        if (nds == null)
          return;

        IDatasetComponent dsComponent = nds as IDatasetComponent;
        IDENetworkDataset deNet = dsComponent.DataElement as IDENetworkDataset;

        INASolver naSolver = naContext.Solver;
        INASolverSettings2 naSolverSettings2 = naSolver as INASolverSettings2;

        if (naSolverSettings2 == null)
          return;

        INetworkAttribute2 netAttribute;
        string attributeName;

        IArray netParameters;
        INetworkAttributeParameter netParameter;
        string paramName;
        int cParameters;

        object paramValue;

        int cAttributes = nds.AttributeCount;
        for (int a = 0; a < cAttributes; ++a)
        {
          netAttribute = nds.get_Attribute(a) as INetworkAttribute2;
          attributeName = netAttribute.Name;
          netParameters = netAttribute.Parameters;

          cParameters = netParameters.Count;
          for (int p = 0; p < cParameters; ++p)
          {
            netParameter = netParameters.get_Element(p) as INetworkAttributeParameter;
            paramName = netParameter.Name;

            paramValue = naSolverSettings2.get_AttributeParameterValue(attributeName, paramName);
            netParameter.Value = paramValue;
          }

          netAttribute.Refresh();
        }
      }
      catch (Exception ex)
      {
        MessageBox.Show(ex.Message, "Push Parameter Values To Network");
      }
    }

    public static bool ParameterExists(INetworkDataset nds, string searchName, VarType vt)
    {
      bool found = false;

      INetworkAttribute2 netAttribute;
      IArray netParams;
      INetworkAttributeParameter netParam;

      int cAttributes = nds.AttributeCount;
      for (int a = 0; a < cAttributes; ++a)
      {
        netAttribute = nds.get_Attribute(a) as INetworkAttribute2;
        netParams = null;
        int cParams = 0;
        if (netAttribute != null)
          netParams = netAttribute.Parameters;

        if (netParams != null)
          cParams = netParams.Count;

        string compareName;
        for (int p = 0; p < cParams; ++p)
        {
          netParam = netParams.get_Element(p) as INetworkAttributeParameter;
          compareName = netParam.Name;
          if (String.Compare(searchName, compareName, true) == 0)
          {
            found = true;
            break;
          }
        }
        if (found)
          break;
      }

      return found;
    }

    public static void ClearEIDArrayParameterValues(INetworkAnalystExtension nax, string baseName)
    {
      try
      {
        INAWindow naWindow = nax.NAWindow;
        INALayer naLayer = null;
        INAContext naContext = null;
        INetworkDataset nds = null;

        naLayer = naWindow.ActiveAnalysis;
        if (naLayer != null)
          naContext = naLayer.Context;

        if (naContext != null)
          nds = naContext.NetworkDataset;

        if (nds == null)
          return;

        VarType vt = SubsetHelperUI.GetEIDArrayParameterType();
        List<string> sourceNames = SubsetHelperUI.FindParameterizedSourceNames(nds, baseName, vt);

        SubsetHelperUI.ClearEIDArrayParameterValues(nax, sourceNames, baseName);
        SubsetHelperUI.PushParameterValuesToNetwork(nax);
      }
      catch (Exception ex)
      {
        string msg = SubsetHelperUI.GetFullExceptionMessage(ex);
        MessageBox.Show(msg, "Clear Network Element Array Parameters");
      }
    }

    private static void ClearEIDArrayParameterValues(INetworkAnalystExtension nax, List<string> sourceNames, string baseName)
    {
      if (nax == null)
        return;

      bool naxEnabled = false;
      IExtensionConfig naxConfig = nax as IExtensionConfig;
      naxEnabled = naxConfig.State == esriExtensionState.esriESEnabled;

      if (!naxEnabled)
        return;

      Dictionary<string, List<int>> eidsBySourceName = new Dictionary<string, List<int>>();
      foreach (string sourceName in sourceNames)
      {
        List<int> eids = null;
        if (!eidsBySourceName.TryGetValue(sourceName, out eids))
          eidsBySourceName.Add(sourceName, null);
      }

      UpdateEIDArrayParameterValuesFromEIDLists(nax, eidsBySourceName, baseName);
    }

    public static void UpdateEIDArrayParameterValuesFromEIDLists(INetworkAnalystExtension nax, Dictionary<string, List<int>> eidsBySourceName, string baseName)
    {
      if (nax == null)
        return;

      bool naxEnabled = false;
      IExtensionConfig naxConfig = nax as IExtensionConfig;
      naxEnabled = naxConfig.State == esriExtensionState.esriESEnabled;

      if (!naxEnabled)
        return;

      INAWindow naWindow = nax.NAWindow;
      INALayer naLayer = null;
      INAContext naContext = null;
      INetworkDataset nds = null;

      naLayer = naWindow.ActiveAnalysis;
      if (naLayer != null)
        naContext = naLayer.Context;

      if (naContext != null)
        nds = naContext.NetworkDataset;

      if (nds == null)
        return;

      IDatasetComponent dsComponent = nds as IDatasetComponent;
      IDENetworkDataset deNet = dsComponent.DataElement as IDENetworkDataset;

      INASolver naSolver = naContext.Solver;
      INASolverSettings2 naSolverSettings2 = naSolver as INASolverSettings2;

      if (naSolverSettings2 == null)
        return;

      string prefix = GetEIDArrayPrefixFromBaseName(baseName);
      VarType vt = GetEIDArrayParameterType();

      int cAttributes = nds.AttributeCount;
      for (int a = 0; a < cAttributes; ++a)
      {
        INetworkAttribute2 netAttribute = nds.get_Attribute(a) as INetworkAttribute2;
        IArray netParams = netAttribute.Parameters;
        int cParams = netParams.Count;
        object paramValue;
        for (int p = 0; p < cParams; ++p)
        {
          INetworkAttributeParameter param = netParams.get_Element(p) as INetworkAttributeParameter;
          if (param.VarType != (int)vt)
            continue;

          string paramName = param.Name;
          string sourceName = GetSourceNameFromParameterName(prefix, paramName);
          if (sourceName.Length == 0)
            continue;

          List<int> eids = null;
          if (eidsBySourceName.TryGetValue(sourceName, out eids))
          {
            if (eids != null)
            {
              if (eids.Count == 0)
                eids = null;
            }
          }

          paramValue = (eids != null) ? eids.ToArray() : null;
          naSolverSettings2.set_AttributeParameterValue(netAttribute.Name, param.Name, paramValue);
        }
      }
    }

    public static void UpdateEIDArrayParameterValuesFromOIDArrays(INetworkAnalystExtension nax, Dictionary<string, ILongArray> oidArraysBySourceName, string baseName)
    {
      Dictionary<string, List<int>> eidsBySourceName = GetEIDListsBySourceName(nax, oidArraysBySourceName, baseName);
      UpdateEIDArrayParameterValuesFromEIDLists(nax, eidsBySourceName, baseName);
    }

    public static void UpdateEIDArrayParameterValuesFromGeometry(INetworkAnalystExtension nax, IGeometry searchGeometry, string baseName)
    {
      Dictionary<string, List<int>> eidsBySourceName = GetEIDListsBySourceName(nax, searchGeometry, baseName);
      UpdateEIDArrayParameterValuesFromEIDLists(nax, eidsBySourceName, baseName);
    }

    private static Dictionary<string, List<int>> GetEIDListsBySourceName(INetworkAnalystExtension nax, object searchObject, string baseName)
    {
      if (nax == null)
        return null;

      bool naxEnabled = false;
      IExtensionConfig naxConfig = nax as IExtensionConfig;
      naxEnabled = naxConfig.State == esriExtensionState.esriESEnabled;

      if (!naxEnabled)
        return null;

      INAWindow naWindow = nax.NAWindow;
      INALayer naLayer = null;
      INAContext naContext = null;
      INetworkDataset nds = null;

      naLayer = naWindow.ActiveAnalysis;
      if (naLayer != null)
        naContext = naLayer.Context;

      if (naContext != null)
        nds = naContext.NetworkDataset;

      INetworkQuery netQuery = nds as INetworkQuery;
      if (netQuery == null)
        return null;

      bool oidSearch = false;
      bool geometrySearch = false;

      if (searchObject == null)
        return null;
      else if (searchObject is Dictionary<string, ILongArray>)
        oidSearch = true;
      else if (searchObject is IGeometry)
        geometrySearch = true;
      else
        return null;

      VarType vt = GetEIDArrayParameterType();
      List<string> sourceNames = FindParameterizedSourceNames(nds, baseName, vt);
      Dictionary<string, List<int>> eidsBySourceName = new Dictionary<string, List<int>>();
      foreach (string sourceName in sourceNames)
      {
        INetworkSource netSource = nds.get_SourceByName(sourceName);
        int sourceID = netSource.ID;
        List<int> eids = new List<int>();

        if (oidSearch)
        {
          Dictionary<string, ILongArray> oidArraysBySourceName = (Dictionary<string, ILongArray>)searchObject;
          ILongArray oids = null;
          IEnumNetworkElement enumNetElement;
          INetworkElement netElement;

          if (oidArraysBySourceName.TryGetValue(sourceName, out oids))
          {
            enumNetElement = netQuery.get_ElementsByOIDs(sourceID, oids);
            enumNetElement.Reset();
            netElement = enumNetElement.Next();
            while (netElement != null)
            {
              eids.Add(netElement.EID);
              netElement = enumNetElement.Next();
            }
          }
        }
        else if (geometrySearch)
        {
          IGeometry searchGeometry = (IGeometry)searchObject;
          if (searchGeometry != null && !searchGeometry.IsEmpty)
          {
            IGeometry elementGeometry = null;
            esriNetworkElementType elementType = esriNetworkElementType.esriNETEdge;
            int eid = -1;

            // Search for the network dataset layer associated with the active analysis layer or create one using the
            // network dataset if matching one not found.
            // If, for example, multiple network dataset layers are added to the map, the active analysis layer
            // might not reference the current network dataset layer (nax.CurrentNetworkLayer).

            INetworkLayer ndsLayer = new NetworkLayerClass();
            ndsLayer.NetworkDataset = nds;

            int count = nax.NetworkLayerCount;
            for (int i = 0; i < count; ++i)
            {
              ndsLayer = nax.get_NetworkLayer(i);
              if (ndsLayer.NetworkDataset == nds)
                break;
              else
                ndsLayer = null;
            }

            if (ndsLayer == null)
            {
              ndsLayer = new NetworkLayerClass();
              ndsLayer.NetworkDataset = nds;
            }

            IEnumLocatedNetworkElement enumLocatedNetElement = null;
            if (ndsLayer != null)
            {
              enumLocatedNetElement = ndsLayer.SearchLocatedNetworkElements(sourceName, searchGeometry);
              enumLocatedNetElement.Reset();
              eid = enumLocatedNetElement.Next(ref elementGeometry, ref elementType);
              while (eid != -1)
              {
                eids.Add(eid);
                eid = enumLocatedNetElement.Next(ref elementGeometry, ref elementType);
              }
            }
          }
        }

        eidsBySourceName.Add(sourceName, eids);
      }

      return eidsBySourceName;
    }

    public static Dictionary<string, ILongArray> GetOIDArraysBySourceNameFromMapSelection(IMap map, List<string> sourceNames)
    {
      UIDClass uid = new UIDClass();
      uid.Value = "{E156D7E5-22AF-11D3-9F99-00C04F6BC78E}"; //IGeoFeatureLayer

      IEnumLayer searchEnumLayer = map.get_Layers(uid, true);
      searchEnumLayer.Reset();

      //create result dictionary from source names with empty oidArrays

      Dictionary<string, ILongArray> oidArraysBySourceName = new Dictionary<string, ILongArray>();
      ILongArray oidArray = null;

      foreach (string sourceName in sourceNames)
      {
        if (!oidArraysBySourceName.TryGetValue(sourceName, out oidArray))
        {
          oidArray = new LongArrayClass();
          oidArraysBySourceName.Add(sourceName, oidArray);
        }
      }

      ILayer layer = searchEnumLayer.Next();
      while (layer != null)
      {
        IDisplayTable displayTable = layer as IDisplayTable;
        string sourceName = "";
        if (layer.Valid && layer.Visible && displayTable != null)
        {
          IDataset ds = displayTable.DisplayTable as IDataset;
          if (ds != null)
            sourceName = ds.Name;
        }

        if (sourceName.Length > 0)
        {
          if (oidArraysBySourceName.TryGetValue(sourceName, out oidArray))
          {
            ISelectionSet selSet = displayTable.DisplaySelectionSet;
            IEnumIDs enumOIDs = null;
            if (selSet != null)
              enumOIDs = selSet.IDs;

            if (enumOIDs != null)
            {
              enumOIDs.Reset();
              int oid = enumOIDs.Next();
              while (oid != -1)
              {
                oidArray.Add(oid);
                oid = enumOIDs.Next();
              }
            }
          }
        }

        layer = searchEnumLayer.Next();
      }

      return oidArraysBySourceName;
    }

    public static IGeometry GetSearchGeometryFromGraphics(IGraphicsContainer graphics)
    {
      IGeometryCollection geometryBag = new GeometryBagClass();
      IElement element;
      IGeometry geometry;

      graphics.Reset();
      element = graphics.Next();

      object before = Type.Missing;
      object after = Type.Missing;

      while (element != null)
      {
        geometry = element.Geometry;
        if (geometry is IPolygon)
          geometryBag.AddGeometry(geometry, ref before, ref after);

        element = graphics.Next();
      }

      IGeometry searchGeometry = geometryBag as IGeometry;

      return searchGeometry;
    }

    public static List<string> FindParameterizedSourceNames(INetworkDataset nds, string baseName, VarType vt)
    {
      List<string> sourceNamesList = new List<string>();
      Dictionary<string, int?> sourceNamesDictionary = new Dictionary<string, int?>();

      int? dummyValue = null;
      int? foundDummyValue = null;

      string prefix = GetEIDArrayPrefixFromBaseName(baseName);

      INetworkSource netSource;
      string sourceName;
      string searchParamName;
      int count = nds.SourceCount;
      for (int i = 0; i < count; ++i)
      {
        netSource = nds.get_Source(i);
        sourceName = netSource.Name;
        if (sourceNamesDictionary.TryGetValue(sourceName, out foundDummyValue))
          continue;

        searchParamName = GetSourceParameterName(prefix, sourceName);

        if (ParameterExists(nds, searchParamName, vt))
        {
          sourceNamesList.Add(sourceName);
          sourceNamesDictionary.Add(sourceName, dummyValue);
        }
      }

      return sourceNamesList;
    }

    public static VarType GetEIDArrayParameterType()
    {
      VarType vt = VarType.Array | VarType.Integer;
      return vt;
    }

    public static string SelectionEIDArrayBaseName
    {
      get
      {
        return FilterSubsetEvaluator.BaseParameterName;
      }
    }

    public static string GraphicsEIDArrayBaseName
    {
      get
      {
        return ScaleSubsetEvaluator.BaseParameterName;
      }
    }

    private static string GetEIDArrayPrefixFromBaseName(string baseName)
    {
      string baseNameEIDArrayModifer = "_eids";
      string prefix = baseName;
      prefix += baseNameEIDArrayModifer;

      return prefix;
    }

    private static string GetSourceNameFromParameterName(string prefix, string paramName)
    {
      string searchSubName = prefix + "_";

      int searchSubNameLen = searchSubName.Length;
      int paramNameLen = paramName.Length;
      if (searchSubNameLen <= 0 || searchSubNameLen >= paramNameLen)
        return "";

      string compareSubName = paramName.Substring(0, searchSubNameLen);
      if (String.Compare(compareSubName, searchSubName, true) != 0)
        return "";

      string sourceName = paramName.Substring(searchSubNameLen);
      return sourceName;
    }

    private static string GetSourceParameterName(string prefix, string sourceName)
    {
      string paramName = prefix;
      paramName += "_";
      paramName += sourceName;

      return paramName;
    }

    public static IExtensionConfig GetNAXConfiguration(IApplication app)
    {
      IExtensionConfig extConfig = null;
      try
      {
        if (app != null)
        {
          UID extCLSID = new UIDClass();
          extCLSID.Value = "{C967BD39-1118-42EE-AAAB-B31642C89C3E}"; // Network Analyst
          extConfig = app.FindExtensionByCLSID(extCLSID) as IExtensionConfig;
        }
      }
      catch
      {
        extConfig = null;
      }

      return extConfig;
    }

    public static string GetFullExceptionMessage(Exception ex)
    {
      string msg = "";
      string subMsg = "";

      while (ex != null)
      {
        subMsg = ex.Message;
        if (subMsg.Length > 0 && msg.Length > 0)
          msg += "\n";

        msg += subMsg;
        ex = ex.InnerException;
      }

      return msg;
    }
  }
}