/*
 * Copyright 2013-2014 Urs Wolfer
 *
 * 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.urswolfer.intellij.plugin.gerrit.ui;

import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.inject.Inject;
import com.intellij.openapi.util.Pair;
import com.intellij.util.ui.ColumnInfo;
import com.intellij.util.ui.ComboBoxCellEditor;
import com.urswolfer.intellij.plugin.gerrit.SelectedRevisions;
import org.jetbrains.annotations.Nullable;

import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.table.TableCellEditor;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Class representing the column in the {@link com.urswolfer.intellij.plugin.gerrit.ui.GerritChangeListPanel} to select
 * a revision for the row's change.
 *
 * @author Thomas Forrer
 */
public class GerritSelectRevisionInfoColumn extends ColumnInfo<ChangeInfo, String> {
    @Inject
    private SelectedRevisions selectedRevisions;

    private final Function<Map.Entry<String, RevisionInfo>, Pair<String, RevisionInfo>> MAP_ENTRY_TO_PAIR = new Function<Map.Entry<String, RevisionInfo>, Pair<String, RevisionInfo>>() {
        @Override
        public Pair<String, RevisionInfo> apply(Map.Entry<String, RevisionInfo> entry) {
            return Pair.create(entry.getKey(), entry.getValue());
        }
    };

    public GerritSelectRevisionInfoColumn() {
        super("Patch Set");
    }

    @Nullable
    @Override
    public String valueOf(ChangeInfo changeInfo) {
        String activeRevision = selectedRevisions.get(changeInfo);
        RevisionInfo revisionInfo = changeInfo.revisions.get(activeRevision);
        return getRevisionLabelFunction(changeInfo).apply(Pair.create(activeRevision, revisionInfo));
    }

    @Override
    public boolean isCellEditable(ChangeInfo changeInfo) {
        return changeInfo.revisions.size() > 1;
    }

    @Nullable
    @Override
    public TableCellEditor getEditor(final ChangeInfo changeInfo) {
        ComboBoxCellEditor editor = new ComboBoxCellEditor() {
            @Override
            protected List<String> getComboBoxItems() {
                Set<Map.Entry<String, RevisionInfo>> revisions = changeInfo.revisions.entrySet();
                return Lists.newArrayList(Iterables.transform(
                                revisions,
                                Functions.compose(getRevisionLabelFunction(changeInfo), MAP_ENTRY_TO_PAIR)
                        )
                );
            }
        };
        editor.addCellEditorListener(new CellEditorListener() {
            @Override
            public void editingStopped(ChangeEvent e) {
                ComboBoxCellEditor cellEditor = (ComboBoxCellEditor) e.getSource();
                String value = (String) cellEditor.getCellEditorValue();
                Iterable<Pair<String, RevisionInfo>> pairs = Iterables.transform(changeInfo.revisions.entrySet(), MAP_ENTRY_TO_PAIR);
                Map<String, Pair<String, RevisionInfo>> map = Maps.uniqueIndex(pairs, getRevisionLabelFunction(changeInfo));
                Pair<String, RevisionInfo> pair = map.get(value);
                selectedRevisions.put(changeInfo.changeId, pair.getFirst());
            }

            @Override
            public void editingCanceled(ChangeEvent e) {

            }
        });
        return editor;
    }

    @Nullable
    @Override
    public String getMaxStringValue() {
        return "100 / 100: eeeeeee";
    }

    private Function<Pair<String, RevisionInfo>, String> getRevisionLabelFunction(final ChangeInfo changeInfo) {
        return new Function<Pair<String, RevisionInfo>, String>() {
            @Override
            public String apply(Pair<String, RevisionInfo> revisionInfo) {
                return String.format("%s / %s: %s",
                        revisionInfo.getSecond()._number,
                        changeInfo.revisions.size(),
                        revisionInfo.getFirst().substring(0, 7));
            }
        };
    }
}

@@ -988,16 +988,70 @@
 Inject;%0A
+import com.intellij.openapi.ui.ComboBoxTableRenderer;%0A
 import c
@@ -1081,16 +1081,16 @@
 l.Pair;%0A
-
 import c
@@ -1397,24 +1397,68 @@
 CellEditor;%0A
+import javax.swing.table.TableCellRenderer;%0A
 import java.
@@ -3028,345 +3028,38 @@
     
-Set%3CMap.Entry%3CString, RevisionInfo%3E%3E revisions = changeInfo.revisions.entrySet();%0A                return Lists.newArrayList(Iterables.transform(%0A                                revisions,%0A                                Functions.compose(getRevisionLabelFunction(changeInfo), MAP_ENTRY_TO_PAIR)%0A                        )%0A                
+return getRevisions(changeInfo
 );%0A 
@@ -3876,30 +3876,16 @@
 ent e) %7B
-%0A%0A            
 %7D%0A      
@@ -3984,24 +3984,24 @@
 ngValue() %7B%0A
-
         retu
@@ -4028,24 +4028,693 @@
 ee%22;%0A    %7D%0A%0A
+    @Nullable%0A    @Override%0A    public TableCellRenderer getRenderer(ChangeInfo changeInfo) %7B%0A        List%3CString%3E revisions = getRevisions(changeInfo);%0A        String%5B%5D array = new String%5Brevisions.size()%5D;%0A        return new ComboBoxTableRenderer%3CString%3E(revisions.toArray(array));%0A    %7D%0A%0A    private List%3CString%3E getRevisions(ChangeInfo changeInfo) %7B%0A        Set%3CMap.Entry%3CString, RevisionInfo%3E%3E revisions = changeInfo.revisions.entrySet();%0A        return Lists.newArrayList(Iterables.transform(%0A                        revisions,%0A                        Functions.compose(getRevisionLabelFunction(changeInfo), MAP_ENTRY_TO_PAIR)%0A                )%0A        );%0A    %7D%0A%0A
     private 

improve column to select patch set in changes list