#include "stdafx.h"

#include "xtr/xtrDesign.h"

using ccl::semantic::RSForm;
using ccl::semantic::RSModel;
using ccl::rslang::TokenID;
using ccl::rslang::ValueClass;
using ccl::semantic::ParsingStatus;
using ccl::semantic::EvalStatus;
using ccl::oss::PictID;
using ccl::oss::OSSchema;
using ccl::lang::ReferenceType;

namespace xtr::design {

static constexpr auto clrMidBlue = RGB(0, 111, 255);
static constexpr auto clrBrown = RGB(150, 70, 0);

CHARFORMAT2W CharFormatRE() noexcept {
  CHARFORMAT2W cf{};
  memset(&cf, 0, sizeof(cf));
  cf.cbSize = sizeof(cf);
  return cf;
}

COLORREF Color(ccl::semantic::ParsingStatus status) noexcept {
  switch (status) {
  case ParsingStatus::INCORRECT: return clrRed;
  case ParsingStatus::UNKNOWN: return clrMidBlue;
  default:
  case ParsingStatus::VERIFIED: return clrGreen;
  }
}

COLORREF Color(const TokenID token) noexcept {
  switch (token) {
  default:
    return clrBlack;

  case TokenID::ID_RADICAL:
    return clrJade;

  case TokenID::ID_GLOBAL:
  case TokenID::ID_FUNCTION:
  case TokenID::ID_PREDICATE:
    return clrPurple;

  case TokenID::BOOL:
  case TokenID::REDUCE:
  case TokenID::DEBOOL:
  case TokenID::BIGPR:
  case TokenID::CARD:
  case TokenID::SMALLPR:
  case TokenID::FILTER:
    return clrBlue;
  }
}

COLORREF Color(const info::CoreStatus status) noexcept {
  switch (status) {
  case info::CoreStatus::CORRECT: return clrGreen;
  case info::CoreStatus::WARNING: return clrYellow;
  default:
  case info::CoreStatus::INCORRECT: return clrRed;
  }
}

COLORREF Color(const info::ModelStatus status) noexcept {
  switch (status) {
  case info::ModelStatus::CORRECT: return clrGreen;
  case info::ModelStatus::WARNING: return clrYellow;
  default:
  case info::ModelStatus::INCORRECT: return clrRed;
  }
}

COLORREF Color(const EvalStatus status) noexcept {
  static constexpr auto clrIncalc = RGB(138, 8, 8);
  switch (status) {
  default:
  case EvalStatus::UNKNOWN:
  case EvalStatus::NEVER_CALCULATED: return clrYellow;
  case EvalStatus::INCALCULABLE: return clrIncalc;
  case EvalStatus::AXIOM_FAIL:
  case EvalStatus::EMPTY:
  case EvalStatus::HAS_DATA: return clrGreen;
  }
}

COLORREF Color(const ValueClass status) noexcept {
  switch (status) {
  default:
  case ValueClass::invalid: return clrBrown;
  case ValueClass::props: return clrTeal;
  case ValueClass::value: return clrGreen;
  }
}

COLORREF Color(const ReferenceType type) noexcept {
  switch (type) {
  default:
  case ReferenceType::invalid: return clrYellow;
  case ReferenceType::entity: return clrYellow;
  case ReferenceType::collaboration: return clrGray200;
  }
}

COLORREF TextColor(const RSForm& schema, const EntityUID target) {
  const auto status = schema.GetParse(target).status;
  if (status == ParsingStatus::UNKNOWN) {
    return clrMidBlue;
  } else if (status == ParsingStatus::INCORRECT) {
    return clrRed;
  } else {
    switch (schema.GetParse(target).valueClass) {
    default:
    case ValueClass::value:  return clrBlack;
    case ValueClass::props: return clrTeal;
    case ValueClass::invalid: return clrBrown;
    }
  }
}

COLORREF TextColor(const RSModel& model, const EntityUID target) {
  static constexpr auto COLOR_INCALC = RGB(255, 102, 0);
  static constexpr auto COLOR_TBA = RGB(57, 30, 174);
  static constexpr auto COLOR_EMPTY = RGB(0, 180, 8);
  static constexpr auto COLOR_FALSE = RGB(255, 0, 102);

  const auto status = model.GetParse(target).status;
  if (status == ParsingStatus::UNKNOWN) {
    return clrMidBlue;
  } else if (status == ParsingStatus::INCORRECT) {
    return clrRed;
  } else if (ccl::semantic::IsCallable(model.GetRS(target).type)) {
    return clrBlack;
  } else {
    switch (model.Calculations()(target)) {
    default: return clrBlack;
    case EvalStatus::INCALCULABLE: return COLOR_INCALC;
    case EvalStatus::NEVER_CALCULATED: return COLOR_TBA;
    case EvalStatus::EMPTY: return COLOR_EMPTY;
    case EvalStatus::AXIOM_FAIL: return COLOR_FALSE;
    }
  }
}

COLORREF BackgroundColor(const RSForm& schema, const EntityUID target) {
  if (!schema.Mods().IsTracking(target)) {
    return clrWhite;
  } else if (schema.Mods()(target)->allowEdit) {
    return clrGray233;
  } else {
    return clrGray211;
  }
}

COLORREF BackgroundColor(const ccl::semantic::RSModel& /*model*/, const EntityUID /*target*/) noexcept {
  return clrWhite;
}

COLORREF BackgroundColor(const OSSchema& oss, const PictID target) {
  static constexpr auto clrPictGreen = RGB(100, 255, 100);
  if (!oss.Ops().HasOperation(target)) {
    return !std::empty(*oss.Src()(target)) ? clrPictGreen : clrRed;
  } else {
    switch (oss.Ops().StatusOf(target)) {
    default:   return clrPictGreen;
    case ccl::ops::Status::undefined:
    case ccl::ops::Status::broken:
    case ccl::ops::Status::defined:
      return clrRed;

    case ccl::ops::Status::outdated:
      return clrYellow;
    }
  }
}

COLORREF BracketsColor(int32_t level) {
  static const auto parColors = std::vector<COLORREF>{
    RGB(238,50, 216),
    RGB(24, 159,17),
    clrBlack,
    RGB(0, 176,240),
    RGB(247,150,70),
    RGB(38, 71, 236)
  };

  if (level < 0) {
    return clrRed;
  } else {
    return parColors.at(level % std::size(parColors));
  }
}

} // namespace xtr::design