/*
 * Copyright (C) 2018 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.strata.basics.date;

import static com.opengamma.strata.collect.Guavate.toImmutableSet;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;

import org.joda.beans.BeanBuilder;
import org.joda.beans.MetaBean;
import org.joda.beans.MetaProperty;
import org.joda.beans.impl.BufferingBeanBuilder;
import org.joda.beans.impl.StandaloneMetaProperty;
import org.joda.beans.ser.DefaultDeserializer;
import org.joda.beans.ser.SerDeserializer;

/**
 * Deserialize {@code ImmutableHolidayCalendar} handling old format.
 */
final class ImmutableHolidayCalendarDeserializer extends DefaultDeserializer {

  /** Singleton instance. */
  public static final SerDeserializer INSTANCE = new ImmutableHolidayCalendarDeserializer();

  private static final MetaProperty<HolidayCalendarId> ID = ImmutableHolidayCalendar.meta().id();
  private static final MetaProperty<Integer> WEEKENDS = ImmutableHolidayCalendar.meta().weekends();
  private static final MetaProperty<Integer> START_YEAR = ImmutableHolidayCalendar.meta().startYear();
  private static final MetaProperty<int[]> LOOKUP = ImmutableHolidayCalendar.meta().lookup();

  @SuppressWarnings({"rawtypes", "unchecked"})
  private static final MetaProperty<Set<String>> HOLIDAYS =
      (MetaProperty) StandaloneMetaProperty.of("holidays", ImmutableHolidayCalendar.meta(), Set.class);
  @SuppressWarnings({"rawtypes", "unchecked"})
  private static final MetaProperty<Set<String>> WEEKEND_DAYS =
      (MetaProperty) StandaloneMetaProperty.of("weekendDays", ImmutableHolidayCalendar.meta(), Set.class);

  //-------------------------------------------------------------------------
  /**
   * Creates an instance.
   */
  private ImmutableHolidayCalendarDeserializer() {
  }

  @Override
  public BeanBuilder<?> createBuilder(Class<?> beanType, MetaBean metaBean) {
    return BufferingBeanBuilder.of(metaBean);
  }

  @Override
  public MetaProperty<?> findMetaProperty(Class<?> beanType, MetaBean metaBean, String propertyName) {
    try {
      return metaBean.metaProperty(propertyName);
    } catch (NoSuchElementException ex) {
      if (HOLIDAYS.name().equals(propertyName)) {
        return HOLIDAYS;
      }
      if (WEEKEND_DAYS.name().equals(propertyName)) {
        return WEEKEND_DAYS;
      }
      throw ex;
    }
  }

  @Override
  public Object build(Class<?> beanType, BeanBuilder<?> builder) {
    ConcurrentMap<MetaProperty<?>, Object> buffer = ((BufferingBeanBuilder<?>) builder).getBuffer();
    HolidayCalendarId id = builder.get(ID);
    if (buffer.containsKey(HOLIDAYS) && buffer.containsKey(WEEKEND_DAYS)) {
      Set<String> holidays = builder.get(HOLIDAYS);
      Set<String> weekendDays = builder.get(WEEKEND_DAYS);
      return ImmutableHolidayCalendar.of(
          id,
          holidays.stream().map(LocalDate::parse).collect(toImmutableSet()),
          weekendDays.stream().map(DayOfWeek::valueOf).collect(toImmutableSet()));
    } else {
      int weekends = builder.get(WEEKENDS);
      int startYear = builder.get(START_YEAR);
      int[] lookup = builder.get(LOOKUP);
      return new ImmutableHolidayCalendar(id, weekends, startYear, lookup, false);
    }
  }

}

@@ -177,76 +177,8 @@
 e;%0A%0A
-import static com.opengamma.strata.collect.Guavate.toImmutableSet;%0A%0A
 impo
@@ -630,16 +630,132 @@
 lizer;%0A%0A
+import com.google.common.reflect.TypeToken;%0Aimport com.opengamma.strata.basics.date.ImmutableHolidayCalendar.Meta;%0A%0A
 /**%0A * D
@@ -1057,72 +1057,123 @@
 Meta
-Property%3CHolidayCalendarId%3E ID = ImmutableHolidayCalendar.meta()
+ META_BEAN = ImmutableHolidayCalendar.meta();%0A  private static final MetaProperty%3CHolidayCalendarId%3E ID = META_BEAN
 .id(
@@ -1235,39 +1235,17 @@
 S = 
-ImmutableHolidayCalendar.meta()
+META_BEAN
 .wee
@@ -1315,39 +1315,17 @@
 R = 
-ImmutableHolidayCalendar.meta()
+META_BEAN
 .sta
@@ -1390,39 +1390,17 @@
 P = 
-ImmutableHolidayCalendar.meta()
+META_BEAN
 .loo
@@ -1443,32 +1443,42 @@
 es%22, %22unchecked%22
+, %22serial%22
 %7D)%0A  private sta
@@ -1504,22 +1504,25 @@
 rty%3CSet%3C
-String
+LocalDate
 %3E%3E HOLID
@@ -1574,16 +1574,27 @@
 erty.of(
+%0A          
 %22holiday
@@ -1601,50 +1601,74 @@
 s%22, 
-ImmutableHolidayCalendar.meta(), Set.class
+META_BEAN, Set.class, new TypeToken%3CSet%3CLocalDate%3E%3E() %7B%7D.getType()
 );%0A 
@@ -1710,16 +1710,26 @@
 checked%22
+, %22serial%22
 %7D)%0A  pri
@@ -1763,22 +1763,25 @@
 rty%3CSet%3C
-String
+DayOfWeek
 %3E%3E WEEKE
@@ -1837,16 +1837,27 @@
 erty.of(
+%0A          
 %22weekend
@@ -1867,50 +1867,74 @@
 s%22, 
-ImmutableHolidayCalendar.meta(), Set.class
+META_BEAN, Set.class, new TypeToken%3CSet%3CDayOfWeek%3E%3E() %7B%7D.getType()
 );%0A%0A
@@ -2974,22 +2974,25 @@
     Set%3C
-String
+LocalDate
 %3E holida
@@ -3029,22 +3029,25 @@
     Set%3C
-String
+DayOfWeek
 %3E weeken
@@ -3126,180 +3126,33 @@
 .of(
-%0A          id,%0A          holidays.stream().map(LocalDate::parse).collect(toImmutableSet()),%0A          weekendDays.stream().map(DayOfWeek::valueOf).collect(toImmutableSet())
+id, holidays, weekendDays
 );%0A 

Fix holiday calendar deserialization