void FeedConditionDialog::ChooseElement(int element_index) {
  // Operator
  LPARAM op_data = operator_combo_.GetItemData(operator_combo_.GetCurSel());
  operator_combo_.ResetContent();

  #define ADD_OPERATOR(op) \
    operator_combo_.AddItem(Aggregator.filter_manager.TranslateOperator(op).c_str(), op);

  switch (element_index) {
    case FEED_FILTER_ELEMENT_META_ID:
    case FEED_FILTER_ELEMENT_EPISODE_NUMBER:
    case FEED_FILTER_ELEMENT_META_DATE_START:
    case FEED_FILTER_ELEMENT_META_DATE_END:
    case FEED_FILTER_ELEMENT_META_EPISODES:
      ADD_OPERATOR(FEED_FILTER_OPERATOR_EQUALS);
      ADD_OPERATOR(FEED_FILTER_OPERATOR_NOTEQUALS);
      ADD_OPERATOR(FEED_FILTER_OPERATOR_ISGREATERTHAN);
      ADD_OPERATOR(FEED_FILTER_OPERATOR_ISGREATERTHANOREQUALTO);
      ADD_OPERATOR(FEED_FILTER_OPERATOR_ISLESSTHAN);
      ADD_OPERATOR(FEED_FILTER_OPERATOR_ISLESSTHANOREQUALTO);
      break;
    case FEED_FILTER_ELEMENT_LOCAL_EPISODE_AVAILABLE:
    case FEED_FILTER_ELEMENT_META_STATUS:
    case FEED_FILTER_ELEMENT_META_TYPE:
    case FEED_FILTER_ELEMENT_USER_STATUS:
      ADD_OPERATOR(FEED_FILTER_OPERATOR_EQUALS);
      ADD_OPERATOR(FEED_FILTER_OPERATOR_NOTEQUALS);
      break;
    case FEED_FILTER_ELEMENT_EPISODE_TITLE:
    case FEED_FILTER_ELEMENT_EPISODE_GROUP:
    case FEED_FILTER_ELEMENT_EPISODE_VIDEO_TYPE:
    case FEED_FILTER_ELEMENT_FILE_TITLE:
    case FEED_FILTER_ELEMENT_FILE_CATEGORY:
    case FEED_FILTER_ELEMENT_FILE_DESCRIPTION:
    case FEED_FILTER_ELEMENT_FILE_LINK:
      ADD_OPERATOR(FEED_FILTER_OPERATOR_EQUALS);
      ADD_OPERATOR(FEED_FILTER_OPERATOR_NOTEQUALS);
      ADD_OPERATOR(FEED_FILTER_OPERATOR_BEGINSWITH);
      ADD_OPERATOR(FEED_FILTER_OPERATOR_ENDSWITH);
      ADD_OPERATOR(FEED_FILTER_OPERATOR_CONTAINS);
      ADD_OPERATOR(FEED_FILTER_OPERATOR_NOTCONTAINS);
      break;
    default:
      for (int i = 0; i < FEED_FILTER_OPERATOR_COUNT; i++) {
        ADD_OPERATOR(i);
      }
  }

  #undef ADD_OPERATOR

  int op_index = operator_combo_.FindItemData(op_data);
  if (op_index == CB_ERR)
    op_index = 0;
  operator_combo_.SetCurSel(op_index);
  
  // ===========================================================================
  
  // Value
  value_combo_.ResetContent();

  RECT rect;
  value_combo_.GetWindowRect(&rect);
  int width = rect.right - rect.left;
  int height = rect.bottom - rect.top;
  ::ScreenToClient(m_hWindow, reinterpret_cast<LPPOINT>(&rect));

  #define RECREATE_COMBO(style) \
    value_combo_.Create(0, WC_COMBOBOX, nullptr, \
      style | CBS_AUTOHSCROLL | WS_CHILD | WS_TABSTOP | WS_VISIBLE | WS_VSCROLL, \
      rect.left, rect.top, width, height * 2, \
      m_hWindow, nullptr, nullptr);

  switch (element_index) {
    case FEED_FILTER_ELEMENT_FILE_CATEGORY:
      RECREATE_COMBO(CBS_DROPDOWN);
      value_combo_.AddString(L"Anime");
      value_combo_.AddString(L"Batch");
      value_combo_.AddString(L"Hentai");
      value_combo_.AddString(L"Non-English");
      value_combo_.AddString(L"Other");
      value_combo_.AddString(L"Raws");
      break;
    case FEED_FILTER_ELEMENT_META_ID:
    case FEED_FILTER_ELEMENT_EPISODE_TITLE: {
      RECREATE_COMBO((element_index == FEED_FILTER_ELEMENT_META_ID ? CBS_DROPDOWNLIST : CBS_DROPDOWN));
      typedef std::pair<int, wstring> anime_pair;
      vector<anime_pair> title_list;
      for (auto it = AnimeDatabase.items.begin(); it != AnimeDatabase.items.end(); ++it) {
        switch (it->second.GetMyStatus()) {
          case mal::MYSTATUS_NOTINLIST:
          case mal::MYSTATUS_COMPLETED:
          case mal::MYSTATUS_DROPPED:
            continue;
          default:
            title_list.push_back(std::make_pair(it->second.GetId(), 
              AnimeDatabase.FindItem(it->second.GetId())->GetTitle()));
        }
      }
      std::sort(title_list.begin(), title_list.end(), 
        [](const anime_pair& a1, const anime_pair& a2) {
          return CompareStrings(a1.second, a2.second) < 0;
        });
      if (element_index == FEED_FILTER_ELEMENT_META_ID) {
        value_combo_.AddString(L"(Unknown)");
      }
      for (auto it = title_list.begin(); it != title_list.end(); ++it) {
        value_combo_.AddItem(it->second.c_str(), it->first);
      }
      break;
    }
    case FEED_FILTER_ELEMENT_META_DATE_START:
    case FEED_FILTER_ELEMENT_META_DATE_END:
      RECREATE_COMBO(CBS_DROPDOWN);
      value_combo_.AddString(static_cast<wstring>(GetDate()).c_str());
      value_combo_.SetCueBannerText(L"YYYY-MM-DD");
      break;
    case FEED_FILTER_ELEMENT_META_STATUS:
      RECREATE_COMBO(CBS_DROPDOWNLIST);
      value_combo_.AddItem(mal::TranslateStatus(mal::STATUS_AIRING).c_str(), mal::STATUS_AIRING);
      value_combo_.AddItem(mal::TranslateStatus(mal::STATUS_FINISHED).c_str(), mal::STATUS_FINISHED);
      value_combo_.AddItem(mal::TranslateStatus(mal::STATUS_NOTYETAIRED).c_str(), mal::STATUS_NOTYETAIRED);
      break;
    case FEED_FILTER_ELEMENT_META_TYPE:
      RECREATE_COMBO(CBS_DROPDOWNLIST);
      value_combo_.AddItem(mal::TranslateType(mal::TYPE_TV).c_str(), mal::TYPE_TV);
      value_combo_.AddItem(mal::TranslateType(mal::TYPE_OVA).c_str(), mal::TYPE_OVA);
      value_combo_.AddItem(mal::TranslateType(mal::TYPE_MOVIE).c_str(), mal::TYPE_MOVIE);
      value_combo_.AddItem(mal::TranslateType(mal::TYPE_SPECIAL).c_str(), mal::TYPE_SPECIAL);
      value_combo_.AddItem(mal::TranslateType(mal::TYPE_ONA).c_str(), mal::TYPE_ONA);
      value_combo_.AddItem(mal::TranslateType(mal::TYPE_MUSIC).c_str(), mal::TYPE_MUSIC);
      break;
    case FEED_FILTER_ELEMENT_USER_STATUS:
      RECREATE_COMBO(CBS_DROPDOWNLIST);
      value_combo_.AddItem(mal::TranslateMyStatus(mal::MYSTATUS_NOTINLIST, false).c_str(), mal::MYSTATUS_NOTINLIST);
      value_combo_.AddItem(mal::TranslateMyStatus(mal::MYSTATUS_WATCHING, false).c_str(), mal::MYSTATUS_WATCHING);
      value_combo_.AddItem(mal::TranslateMyStatus(mal::MYSTATUS_COMPLETED, false).c_str(), mal::MYSTATUS_COMPLETED);
      value_combo_.AddItem(mal::TranslateMyStatus(mal::MYSTATUS_ONHOLD, false).c_str(), mal::MYSTATUS_ONHOLD);
      value_combo_.AddItem(mal::TranslateMyStatus(mal::MYSTATUS_DROPPED, false).c_str(), mal::MYSTATUS_DROPPED);
      value_combo_.AddItem(mal::TranslateMyStatus(mal::MYSTATUS_PLANTOWATCH, false).c_str(), mal::MYSTATUS_PLANTOWATCH);
      break;
    case FEED_FILTER_ELEMENT_EPISODE_NUMBER:
    case FEED_FILTER_ELEMENT_META_EPISODES:
      RECREATE_COMBO(CBS_DROPDOWN);
      value_combo_.AddString(L"%watched%");
      value_combo_.AddString(L"%total%");
      break;
    case FEED_FILTER_ELEMENT_EPISODE_VERSION:
      RECREATE_COMBO(CBS_DROPDOWN);
      value_combo_.AddString(L"2");
      value_combo_.AddString(L"3");
      value_combo_.AddString(L"4");
      value_combo_.AddString(L"0");
      break;
    case FEED_FILTER_ELEMENT_LOCAL_EPISODE_AVAILABLE:
      RECREATE_COMBO(CBS_DROPDOWNLIST);
      value_combo_.AddString(L"False");
      value_combo_.AddString(L"True");
      break;
    case FEED_FILTER_ELEMENT_EPISODE_VIDEO_RESOLUTION:
      RECREATE_COMBO(CBS_DROPDOWN);
      value_combo_.AddString(L"1080p");
      value_combo_.AddString(L"720p");
      value_combo_.AddString(L"480p");
      value_combo_.AddString(L"400p");
      break;
    case FEED_FILTER_ELEMENT_EPISODE_VIDEO_TYPE:
      RECREATE_COMBO(CBS_DROPDOWN);
      value_combo_.AddString(L"h264");
      value_combo_.AddString(L"x264");
      value_combo_.AddString(L"XviD");
      break;
    default:
      RECREATE_COMBO(CBS_DROPDOWN);
      break;
  }

  #undef RECREATE_COMBO
  value_combo_.SetCurSel(0);
}
void FeedConditionDialog::ChooseElement(int element_index) {
  // Operator
  LPARAM op_data = operator_combo_.GetItemData(operator_combo_.GetCurSel());
  operator_combo_.ResetContent();

  #define ADD_OPERATOR(op) \
    operator_combo_.AddItem(Aggregator.filter_manager.TranslateOperator(op).c_str(), op);

  switch (element_index) {
    case kFeedFilterElement_Meta_Id:
    case kFeedFilterElement_Episode_Number:
    case kFeedFilterElement_Meta_DateStart:
    case kFeedFilterElement_Meta_DateEnd:
    case kFeedFilterElement_Meta_Episodes:
      ADD_OPERATOR(kFeedFilterOperator_Equals);
      ADD_OPERATOR(kFeedFilterOperator_NotEquals);
      ADD_OPERATOR(kFeedFilterOperator_IsGreaterThan);
      ADD_OPERATOR(kFeedFilterOperator_IsGreaterThanOrEqualTo);
      ADD_OPERATOR(kFeedFilterOperator_IsLessThan);
      ADD_OPERATOR(kFeedFilterOperator_IsLessThanOrEqualTo);
      break;
    case kFeedFilterElement_Local_EpisodeAvailable:
    case kFeedFilterElement_Meta_Status:
    case kFeedFilterElement_Meta_Type:
    case kFeedFilterElement_User_Status:
      ADD_OPERATOR(kFeedFilterOperator_Equals);
      ADD_OPERATOR(kFeedFilterOperator_NotEquals);
      break;
    case kFeedFilterElement_Episode_Title:
    case kFeedFilterElement_Episode_Group:
    case kFeedFilterElement_Episode_VideoType:
    case kFeedFilterElement_File_Title:
    case kFeedFilterElement_File_Category:
    case kFeedFilterElement_File_Description:
    case kFeedFilterElement_File_Link:
      ADD_OPERATOR(kFeedFilterOperator_Equals);
      ADD_OPERATOR(kFeedFilterOperator_NotEquals);
      ADD_OPERATOR(kFeedFilterOperator_BeginsWith);
      ADD_OPERATOR(kFeedFilterOperator_EndsWith);
      ADD_OPERATOR(kFeedFilterOperator_Contains);
      ADD_OPERATOR(kFeedFilterOperator_NotContains);
      break;
    default:
      for (int i = 0; i < kFeedFilterOperator_Count; i++) {
        ADD_OPERATOR(i);
      }
  }

  #undef ADD_OPERATOR

  int op_index = operator_combo_.FindItemData(op_data);
  if (op_index == CB_ERR)
    op_index = 0;
  operator_combo_.SetCurSel(op_index);

  //////////////////////////////////////////////////////////////////////////////
  // Value

  value_combo_.ResetContent();

  RECT rect;
  value_combo_.GetWindowRect(&rect);
  int width = rect.right - rect.left;
  int height = rect.bottom - rect.top;
  ::ScreenToClient(GetWindowHandle(), reinterpret_cast<LPPOINT>(&rect));

  #define RECREATE_COMBO(style) \
    value_combo_.Create(0, WC_COMBOBOX, nullptr, \
        style | CBS_AUTOHSCROLL | WS_CHILD | WS_TABSTOP | WS_VISIBLE | WS_VSCROLL, \
        rect.left, rect.top, width, height * 2, \
        GetWindowHandle(), nullptr, nullptr);

  switch (element_index) {
    case kFeedFilterElement_File_Category:
      RECREATE_COMBO(CBS_DROPDOWN);
      value_combo_.AddString(L"Anime");
      value_combo_.AddString(L"Batch");
      value_combo_.AddString(L"Hentai");
      value_combo_.AddString(L"Non-English");
      value_combo_.AddString(L"Other");
      value_combo_.AddString(L"Raws");
      break;
    case kFeedFilterElement_Meta_Id:
    case kFeedFilterElement_Episode_Title: {
      RECREATE_COMBO((element_index == kFeedFilterElement_Meta_Id ? CBS_DROPDOWNLIST : CBS_DROPDOWN));
      typedef std::pair<int, std::wstring> anime_pair;
      std::vector<anime_pair> title_list;
      for (auto it = AnimeDatabase.items.begin(); it != AnimeDatabase.items.end(); ++it) {
        switch (it->second.GetMyStatus()) {
          case anime::kNotInList:
          case anime::kCompleted:
          case anime::kDropped:
            continue;
          default:
            title_list.push_back(std::make_pair(
                it->second.GetId(),
                AnimeDatabase.FindItem(it->second.GetId())->GetTitle()));
        }
      }
      std::sort(title_list.begin(), title_list.end(),
        [](const anime_pair& a1, const anime_pair& a2) {
          return CompareStrings(a1.second, a2.second) < 0;
        });
      if (element_index == kFeedFilterElement_Meta_Id)
        value_combo_.AddString(L"(Unknown)");
      foreach_(it, title_list)
        value_combo_.AddItem(it->second.c_str(), it->first);
      break;
    }
    case kFeedFilterElement_Meta_DateStart:
    case kFeedFilterElement_Meta_DateEnd:
      RECREATE_COMBO(CBS_DROPDOWN);
      value_combo_.AddString(static_cast<std::wstring>(GetDate()).c_str());
      value_combo_.SetCueBannerText(L"YYYY-MM-DD");
      break;
    case kFeedFilterElement_Meta_Status:
      RECREATE_COMBO(CBS_DROPDOWNLIST);
      value_combo_.AddItem(anime::TranslateStatus(anime::kAiring).c_str(), anime::kAiring);
      value_combo_.AddItem(anime::TranslateStatus(anime::kFinishedAiring).c_str(), anime::kFinishedAiring);
      value_combo_.AddItem(anime::TranslateStatus(anime::kNotYetAired).c_str(), anime::kNotYetAired);
      break;
    case kFeedFilterElement_Meta_Type:
      RECREATE_COMBO(CBS_DROPDOWNLIST);
      value_combo_.AddItem(anime::TranslateType(anime::kTv).c_str(), anime::kTv);
      value_combo_.AddItem(anime::TranslateType(anime::kOva).c_str(), anime::kOva);
      value_combo_.AddItem(anime::TranslateType(anime::kMovie).c_str(), anime::kMovie);
      value_combo_.AddItem(anime::TranslateType(anime::kSpecial).c_str(), anime::kSpecial);
      value_combo_.AddItem(anime::TranslateType(anime::kOna).c_str(), anime::kOna);
      value_combo_.AddItem(anime::TranslateType(anime::kMusic).c_str(), anime::kMusic);
      break;
    case kFeedFilterElement_User_Status:
      RECREATE_COMBO(CBS_DROPDOWNLIST);
      value_combo_.AddItem(anime::TranslateMyStatus(anime::kNotInList, false).c_str(), anime::kNotInList);
      value_combo_.AddItem(anime::TranslateMyStatus(anime::kWatching, false).c_str(), anime::kWatching);
      value_combo_.AddItem(anime::TranslateMyStatus(anime::kCompleted, false).c_str(), anime::kCompleted);
      value_combo_.AddItem(anime::TranslateMyStatus(anime::kOnHold, false).c_str(), anime::kOnHold);
      value_combo_.AddItem(anime::TranslateMyStatus(anime::kDropped, false).c_str(), anime::kDropped);
      value_combo_.AddItem(anime::TranslateMyStatus(anime::kPlanToWatch, false).c_str(), anime::kPlanToWatch);
      break;
    case kFeedFilterElement_Episode_Number:
    case kFeedFilterElement_Meta_Episodes:
      RECREATE_COMBO(CBS_DROPDOWN);
      value_combo_.AddString(L"%watched%");
      value_combo_.AddString(L"%total%");
      break;
    case kFeedFilterElement_Episode_Version:
      RECREATE_COMBO(CBS_DROPDOWN);
      value_combo_.AddString(L"2");
      value_combo_.AddString(L"3");
      value_combo_.AddString(L"4");
      value_combo_.AddString(L"0");
      break;
    case kFeedFilterElement_Local_EpisodeAvailable:
      RECREATE_COMBO(CBS_DROPDOWNLIST);
      value_combo_.AddString(L"False");
      value_combo_.AddString(L"True");
      break;
    case kFeedFilterElement_Episode_VideoResolution:
      RECREATE_COMBO(CBS_DROPDOWN);
      value_combo_.AddString(L"1080p");
      value_combo_.AddString(L"720p");
      value_combo_.AddString(L"480p");
      value_combo_.AddString(L"400p");
      break;
    case kFeedFilterElement_Episode_VideoType:
      RECREATE_COMBO(CBS_DROPDOWN);
      value_combo_.AddString(L"h264");
      value_combo_.AddString(L"x264");
      value_combo_.AddString(L"XviD");
      break;
    default:
      RECREATE_COMBO(CBS_DROPDOWN);
      break;
  }

  #undef RECREATE_COMBO
  value_combo_.SetCurSel(0);
}