package editor.database.card;

import java.time.LocalDate;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import editor.collection.CardList;
import editor.collection.deck.CategorySpec;
import editor.collection.deck.Deck;
import editor.database.characteristics.CardAttribute;
import editor.util.CollectionUtils;

/**
 * This class represents a method of formatting a card into a string.  It takes
 * a format string, which consists of arbitrary characters and format specifiers,
 * and replaces the format specifiers with the corresponding values of a card
 * in a deck.  A format specifier consists of the name of a {@link CardAttribute}
 * surrounded by braces ({}).
 *
 * @author Alec Roelke
 */
public class CardFormat
{
    /**
     * This class represents a "fake" card entry that reports static data about a card.
     * It always returns 1 for count, the card's release date for date, and an empty
     * set for categories.
     *
     * @author Alec Roelke
     */
    private static class FakeEntry implements CardList.Entry
    {
        /**
         * Card so the release date can be known.
         */
        private final Card card;

        /**
         * Create a new FakeEntry.
         *
         * @param c card for the new entry
         */
        public FakeEntry(Card c)
        {
            card = c;
        }

        @Override
        public Card card()
        {
            return card;
        }

        @Override
        public Set<CategorySpec> categories()
        {
            return Collections.emptySet();
        }

        @Override
        public int count()
        {
            return 1;
        }

        @Override
        public LocalDate dateAdded()
        {
            return card.expansion().releaseDate;
        }

    }

    /**
     * Format specifier for a card.
     */
    public final String format;

    /**
     * Create a new CardFormat.
     *
     * @param pattern format specifier for a card
     */
    public CardFormat(String pattern)
    {
        format = pattern;
    }

    /**
     * Format a card using this CardFormat's format specifier.  Deck-dependent
     * values will be statically assigned:
     * {@link CardAttribute#COUNT}: 1
     * {@link CardAttribute#CATEGORIES}: empty set
     * {@link CardAttribute#DATE_ADDED}: the card's release date
     *
     * @param card card to format
     * @return the formatted string
     */
    public String format(Card card)
    {
        return format(new FakeEntry(card));
    }

    /**
     * Format a card using this CardFormat's format specifier.  Deck-dependent
     * values will be taken from the entry provided.
     *
     * @param card entry for the card to format
     * @return the formatted string
     */
    public String format(CardList.Entry card)
    {
        String pattern = format;
        for (CardAttribute type : CardAttribute.values())
        {
            String replacement = '{' + type.toString().toLowerCase() + '}';
            switch (type)
            {
            case MANA_COST:
            case POWER:
            case TOUGHNESS:
            case LOYALTY:
                pattern = pattern.replace(replacement, String.join(' ' + Card.FACE_SEPARATOR + ' ',
                        ((List<?>)card.get(type)).stream().map(String::valueOf).collect(Collectors.toList())));
                break;
            case CMC:
                pattern = pattern.replace(replacement, String.join(' ' + Card.FACE_SEPARATOR + ' ',
                        CollectionUtils.convertToList(card.get(type), Double.class).stream().map((n) -> {
                            if (n == n.intValue())
                                return Integer.toString(n.intValue());
                            else
                                return n.toString();
                        }).collect(Collectors.toList())));
                break;
            case COLORS:
            case COLOR_IDENTITY:
                pattern = pattern.replace(replacement, String.join(",",
                        ((List<?>)card.get(type)).stream().map(String::valueOf).collect(Collectors.toList())));
                break;
            case CATEGORIES:
                pattern = pattern.replace(replacement, String.join(",",
                        CollectionUtils.convertToSet(card.get(type), CategorySpec.class).stream().map(CategorySpec::getName).sorted().collect(Collectors.toList())));
                break;
            case DATE_ADDED:
                pattern = pattern.replace(replacement, Deck.DATE_FORMATTER.format((LocalDate)card.get(type)));
                break;
            default:
                pattern = pattern.replace(replacement, String.valueOf(card.get(type)));
                break;
            }
        }
        return pattern;
    }
}

@@ -3043,16 +3043,55 @@
         
+ pattern = pattern.replace(replacement,
  switch 
@@ -3100,23 +3100,15 @@
 ype)
+ %7B
 %0A    
-        %7B%0A
     
@@ -3133,142 +3133,38 @@
 COST
-:%0A            case POWER:%0A            case TOUGHNESS:%0A            case LOYALTY:%0A                pattern = pattern.replace(replacement,
+, POWER, TOUGHNESS, LOYALTY -%3E
  Str
@@ -3197,36 +3197,32 @@
 EPARATOR + ' ',%0A
-    
                 
@@ -3302,33 +3302,32 @@
 ctors.toList()))
-)
 ;%0A              
@@ -3332,91 +3332,19 @@
     
-break;%0A            case CMC:%0A                pattern = pattern.replace(replacement,
+case CMC -%3E
  Str
@@ -3377,36 +3377,32 @@
 EPARATOR + ' ',%0A
-    
                 
@@ -3511,20 +3511,16 @@
         
-    
 if (n ==
@@ -3558,28 +3558,24 @@
             
-   
- 
 return Integ
@@ -3597,28 +3597,24 @@
 ntValue());%0A
-    
             
@@ -3654,28 +3654,24 @@
             
-    
 return n.toS
@@ -3699,20 +3699,16 @@
         
- 
-   
 %7D).colle
@@ -3723,33 +3723,32 @@
 ctors.toList()))
-)
 ;%0A              
@@ -3753,127 +3753,38 @@
     
-break;%0A            case COLORS:%0A            case COLOR_IDENTITY:%0A                pattern = pattern.replace(replacement,
+case COLORS, COLOR_IDENTITY -%3E
  Str
@@ -3789,36 +3789,32 @@
 tring.join(%22,%22,%0A
-    
                 
@@ -3894,33 +3894,32 @@
 ctors.toList()))
-)
 ;%0A              
@@ -3924,98 +3924,26 @@
     
-break;%0A            case CATEGORIES:%0A                pattern = pattern.replace(replacement,
+case CATEGORIES -%3E
  Str
@@ -3948,36 +3948,32 @@
 tring.join(%22,%22,%0A
-    
                 
@@ -4115,17 +4115,16 @@
 List()))
-)
 ;%0A      
@@ -4137,98 +4137,26 @@
     
-break;%0A            case DATE_ADDED:%0A                pattern = pattern.replace(replacement,
+case DATE_ADDED -%3E
  Dec
@@ -4197,33 +4197,32 @@
 )card.get(type))
-)
 ;%0A              
@@ -4227,90 +4227,18 @@
     
-break;%0A            default:%0A                pattern = pattern.replace(replacement,
+default -%3E
  Str
@@ -4264,17 +4264,16 @@
 t(type))
-)
 ;%0A      
@@ -4282,32 +4282,11 @@
     
-    break;%0A            %7D
+%7D);
 %0A   

Use switch expression for replacement pattern