#pragma once
#include "SearchCondition.h"
#include <list>
#include <functional>

using namespace System::Collections::Generic;
using namespace std;

ref class ConditionHelper
{
public:
  static Condition^ ConditionFrom(list<SearchConditionPtr>& searchConditions) {
    auto conditions = gcnew List<Condition^>();

    for(auto condition = searchConditions.begin(); condition != searchConditions.end(); ++condition) {
      conditions->Add(ConditionFrom(*condition));
    }

    if(conditions->Count == 1) {
        conditions->Add(Condition::TrueCondition);
    }

    return gcnew AndCondition(conditions->ToArray());
  }

  static Condition^ ConditionFrom(SearchConditionPtr searchCondition) {
    auto automationProperty = AutomationProperty::LookupById(searchCondition->propertyId);
    Object^ value = nullptr;

    if(automationProperty == AutomationElement::ControlTypeProperty) {
      return Or(searchCondition->numbers, searchCondition->numbersCount, ControlType);
    } else if(searchCondition->IsString()) {
      value = gcnew String(searchCondition->string);
    } else if(searchCondition->IsPattern()) {
      return Or(searchCondition->patterns, searchCondition->patternsCount, Pattern);
    } else {
      value = searchCondition->number;
    }

    return gcnew PropertyCondition(automationProperty, value);
  }

private:
  static Condition^ Or(const int* ids, const int count, std::function<Condition^(int)> conditionFor) {
    if( count == 1 ) {
      return conditionFor(ids[0]);
    }

    auto conditions = gcnew List<Condition^>();
    for(auto index = 0; index < count; ++index) {
      conditions->Add(conditionFor(ids[index]));
    }

    return gcnew OrCondition(conditions->ToArray());
  }

  static Condition^ ControlType(const int id) {
    return gcnew PropertyCondition(AutomationElement::ControlTypeProperty, ControlType::LookupById(id));
  }

  static Condition^ Pattern(const int patternId) {
    return gcnew PropertyCondition(AutomationProperty::LookupById(patternId), true);
  }
};