/*
 * Copyright 2000-2014 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.lang.javascript.boilerplate;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.intellij.ide.util.projectWizard.SettingsStep;
import com.intellij.openapi.ui.ValidationInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.platform.WebProjectGenerator;
import com.intellij.platform.templates.github.GithubTagInfo;
import com.intellij.ui.ListCellRendererWrapper;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.ReloadableComboBoxPanel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.util.*;

/**
 * @author Sergey Simonchik
 */
public class GithubProjectGeneratorPeer implements WebProjectGenerator.GeneratorPeer<GithubTagInfo> {
  private void createUIComponents() {
    myReloadableComboBoxPanel = new ReloadableComboBoxPanel<GithubTagInfo>() {

      @SuppressWarnings("unchecked")
      @Override
      protected void doUpdateValues(@NotNull Set<GithubTagInfo> tags) {
        if (!shouldUpdate(tags)) {
          return;
        }

        List<GithubTagInfo> sortedTags = createSortedTagList(tags);
        GithubTagInfo selectedItem = getSelectedValue();
        if (selectedItem == null && sortedTags.size() > 0) {
          selectedItem = sortedTags.get(0);
        }
        myComboBox.removeAllItems();
        myComboBox.addItem(myMasterTag);
        for (GithubTagInfo tag : sortedTags) {
          myComboBox.addItem(tag);
        }
        if (selectedItem != null) {
          // restore previously selected item
          for (int i = 0; i < myComboBox.getItemCount(); i++) {
            GithubTagInfo item = GithubTagInfo.tryCast(myComboBox.getItemAt(i));
            if (item != null && item.getName().equals(selectedItem.getName())) {
              myComboBox.setSelectedIndex(i);
              break;
            }
          }
        }
        myComboBox.updateUI();
        fireStateChanged();
      }

      private boolean shouldUpdate(Set<GithubTagInfo> newTags) {
        if (myComboBox.getItemCount() == 0) {
          return true;
        }
        int count = myComboBox.getItemCount();
        Set<GithubTagInfo> oldTags = Sets.newHashSet();
        for (int i = 1; i < count; i++) {
          GithubTagInfo item = ObjectUtils.tryCast(myComboBox.getItemAt(i), GithubTagInfo.class);
          if (item != null) {
            oldTags.add(item);
          }
        }
        return !oldTags.equals(newTags);
      }

      @SuppressWarnings("unchecked")
      @NotNull
      @Override
      protected JComboBox createValuesComboBox() {
        JComboBox box = super.createValuesComboBox();
        box.setRenderer(new ListCellRendererWrapper<GithubTagInfo>() {
          @Override
          public void customize(JList list, GithubTagInfo tag, int index, boolean selected, boolean hasFocus) {
            final String text;
            if (tag == null) {
              text = isBackgroundJobRunning() ? "Loading..." : "Unavailable";
            }
            else {
              text = tag.getName();
            }
            setText(text);
          }
        });

        return box;
      }
    };

    myVersionPanel = myReloadableComboBoxPanel.getMainPanel();
  }

  private final List<WebProjectGenerator.SettingsStateListener> myListeners = ContainerUtil.newArrayList();
  private final GithubTagInfo myMasterTag;
  private final GithubTagListProvider myTagListProvider;
  private JComponent myComponent;
  private JPanel myVersionPanel;
  private ReloadableComboBoxPanel<GithubTagInfo> myReloadableComboBoxPanel;

  public GithubProjectGeneratorPeer(@NotNull AbstractGithubTagDownloadedProjectGenerator generator) {
    String ghUserName = generator.getGithubUserName();
    String ghRepoName = generator.getGithubRepositoryName();
    myMasterTag = new GithubTagInfo(
      "master",
      String.format("https://github.com/%s/%s/zipball/master", ghUserName, ghRepoName)
    );

    myTagListProvider = new GithubTagListProvider(ghUserName, ghRepoName);

    myReloadableComboBoxPanel.setDataProvider(new ReloadableComboBoxPanel.DataProvider<GithubTagInfo>() {
      @Override
      public Set<GithubTagInfo> getCachedValues() {
        return myTagListProvider.getCachedTags();
      }

      @Override
      public void updateValuesAsynchronously() {
        myTagListProvider.updateTagListAsynchronously(GithubProjectGeneratorPeer.this);
      }
    });

    myReloadableComboBoxPanel.reloadValuesInBackground();
  }

  void onTagsUpdated(@NotNull ImmutableSet<GithubTagInfo> tags) {
    myReloadableComboBoxPanel.onUpdateValues(tags);
  }

  void onTagsUpdateError(@NotNull final String errorMessage) {
    myReloadableComboBoxPanel.onValuesUpdateError(errorMessage);
  }

  @NotNull
  private static List<GithubTagInfo> createSortedTagList(@NotNull Collection<GithubTagInfo> tags) {
    List<GithubTagInfo> sortedTags = ContainerUtil.newArrayList(tags);
    Collections.sort(sortedTags, new Comparator<GithubTagInfo>() {
      @Override
      public int compare(GithubTagInfo tag1, GithubTagInfo tag2) {
        GithubTagInfo.Version v1 = tag1.getVersion();
        GithubTagInfo.Version v2 = tag2.getVersion();
        return v2.compareTo(v1);
      }
    });
    for (GithubTagInfo tag : sortedTags) {
      tag.setRecentTag(false);
    }
    if (!sortedTags.isEmpty()) {
      sortedTags.get(0).setRecentTag(true);
    }
    return sortedTags;
  }


  @NotNull
  @Override
  public JComponent getComponent() {
    return myComponent;
  }

  @Override
  public void buildUI(@NotNull SettingsStep settingsStep) {
    settingsStep.addSettingsField("&Version:", myVersionPanel);
    settingsStep.addSettingsComponent(myReloadableComboBoxPanel.getErrorComponent());
  }

  @NotNull
  @Override
  public GithubTagInfo getSettings() {
    GithubTagInfo tag = myReloadableComboBoxPanel.getSelectedValue();
    if (tag == null) {
      throw new RuntimeException("[internal error] No versions available.");
    }
    return tag;
  }

  @Override
  @Nullable
  public ValidationInfo validate() {
    GithubTagInfo tag = myReloadableComboBoxPanel.getSelectedValue();
    if (tag != null) {
      return null;
    }
    String errorMessage = StringUtil.notNullize(myReloadableComboBoxPanel.getErrorComponent().getText());
    if (errorMessage.isEmpty()) {
      errorMessage = "Versions have not been loaded yet.";
    }
    return new ValidationInfo(errorMessage);
  }

  @Override
  public boolean isBackgroundJobRunning() {
    return myReloadableComboBoxPanel.isBackgroundJobRunning();
  }

  @Override
  public void addSettingsStateListener(@NotNull WebProjectGenerator.SettingsStateListener listener) {
    myListeners.add(listener);
  }


  private void fireStateChanged() {
    GithubTagInfo tag = myReloadableComboBoxPanel.getSelectedValue();
    for (WebProjectGenerator.SettingsStateListener listener : myListeners) {
      listener.stateChanged(tag != null);
    }
  }
}

@@ -731,16 +731,48 @@
 t.Sets;%0A
+import com.intellij.BundleBase;%0A
 import c
@@ -6348,16 +6348,52 @@
 gsField(
+BundleBase.replaceMnemonicAmpersand(
 %22&Versio
@@ -6395,16 +6395,17 @@
 ersion:%22
+)
 , myVers

fix showing mnemonic