/*
 * LensKit, an open source recommender systems toolkit.
 * Copyright 2010-2013 Regents of the University of Minnesota and contributors
 * Work on LensKit has been funded by the National Science Foundation under
 * grants IIS 05-34939, 08-08692, 08-12148, and 10-17697.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 51
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
package org.grouplens.lenskit.scored;

import com.google.common.collect.ImmutableMap;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import it.unimi.dsi.fastutil.objects.*;
import org.grouplens.lenskit.symbols.Symbol;
import org.grouplens.lenskit.symbols.TypedSymbol;

import javax.annotation.Nonnull;
import java.io.Serializable;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

class ScoredIdImpl extends AbstractScoredId implements Serializable {
    private static final long serialVersionUID = 1L;

    private final long id;
    private final double score;
    @SuppressFBWarnings("SE_BAD_FIELD")
    @Nonnull
    private final Reference2DoubleMap<Symbol> channelMap;
    @SuppressFBWarnings("SE_BAD_FIELD")
    @Nonnull
    private final Map<TypedSymbol<?>, ?> typedChannelMap;

    public ScoredIdImpl(long id, double score) {
        this(id, score, null, null);
    }

    /**
     * @param typedChannelMap a map from TypedSymbol<K> to the object in that side channel. 
     *                        It is assumed that for each key TypedSymbol<K> in the map that the value
     *                        is of type K.  
     */
    public ScoredIdImpl(long id, double score, Reference2DoubleMap<Symbol> channelMap, 
            Reference2ObjectMap<TypedSymbol<?>, ?> typedChannelMap) {
        this.id = id;
        this.score = score;
        if (channelMap != null) {
            this.channelMap = new Reference2DoubleArrayMap<Symbol>(channelMap);
        } else {
            this.channelMap = Reference2DoubleMaps.EMPTY_MAP;
        }
        if (typedChannelMap != null) {
            this.typedChannelMap = ImmutableMap.copyOf(typedChannelMap);
        } else {
            this.typedChannelMap = Collections.emptyMap();
        }
    }

    @Override
    public long getId() {
        return id;
    }

    @Override
    public double getScore() {
        return score;
    }

    @Override
    public boolean hasChannel(Symbol s) {
        return channelMap.containsKey(s);
    }

    @Override
    public boolean hasChannel(TypedSymbol<?> s) {
        return typedChannelMap.containsKey(s);
    }

    @Override
    public double channel(Symbol s) {
        if (hasChannel(s)) {
            return channelMap.get(s);
        }
        throw new IllegalArgumentException("No existing channel under name " + s.getName());
    }

    @SuppressWarnings("unchecked")
    @Override
    public <K> K channel(TypedSymbol<K> s) {
        if (hasChannel(s)) {
            return (K) typedChannelMap.get(s);
        }
        throw new IllegalArgumentException("No existing typed channel under name " + s.getName());
    }

    @Override
    public Set<Symbol> getChannels() {
        return Collections.unmodifiableSet(channelMap.keySet());
    }

    @Override
    public Set<TypedSymbol<?>> getTypedChannels() {
        return typedChannelMap.keySet();
    }
}

@@ -1705,19 +1705,17 @@
  channel
-Map
+s
 ;%0A    @S
@@ -1814,19 +1814,17 @@
 dChannel
-Map
+s
 ;%0A%0A    p
@@ -1930,242 +1930,188 @@
   * 
-@param typedChannelMap a map from TypedSymbol%3CK%3E to the object in that side channel. %0A     *                        It is assumed
+Construct a new %7B@link ScoredId%7D.%0A     * @param id The ID.%0A     * @param score The score.%0A     * @param chans The side channel map.%0A     * @param
  t
+C
 ha
-t for each key TypedSymbol%3CK%3E in the map that the value%0A     *                        is of type K.  
+ns The typed side channel map.
 %0A   
@@ -2198,16 +2198,10 @@
 chan
-nelMap, 
+s,
 %0A   
@@ -2249,30 +2249,21 @@
 ?%3E, ?%3E t
-ypedChannelMap
+Chans
 ) %7B%0A    
@@ -2324,22 +2324,17 @@
 if (chan
-nelMap
+s
  != null
@@ -2361,19 +2361,17 @@
 .channel
-Map
+s
  = new R
@@ -2406,22 +2406,17 @@
 ol%3E(chan
-nelMap
+s
 );%0A     
@@ -2451,19 +2451,17 @@
 .channel
-Map
+s
  = Refer
@@ -2510,30 +2510,21 @@
    if (t
-ypedChannelMap
+Chans
  != null
@@ -2556,19 +2556,17 @@
 dChannel
-Map
+s
  = Immut
@@ -2581,30 +2581,21 @@
 copyOf(t
-ypedChannelMap
+Chans
 );%0A     
@@ -2635,19 +2635,17 @@
 dChannel
-Map
+s
  = Colle
@@ -2894,27 +2894,25 @@
 turn channel
-Map
+s
 .containsKey
@@ -3014,19 +3014,17 @@
 dChannel
-Map
+s
 .contain
@@ -3142,27 +3142,25 @@
 turn channel
-Map
+s
 .get(s);%0A   
@@ -3424,19 +3424,17 @@
 dChannel
-Map
+s
 .get(s);
@@ -3649,27 +3649,25 @@
 eSet(channel
-Map
+s
 .keySet());%0A
@@ -3766,19 +3766,17 @@
 dChannel
-Map
+s
 .keySet(

Clean up constructor docs for the scored ID impl.