/*
 * Copyright 2013-present Facebook, Inc.
 *
 * 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.facebook.buck.android;

import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.collect.TreeMultimap;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.Map;
import java.util.TreeMap;

/**
 * Represents string resources of types string, plural and array for a locale. Also responsible
 * for generating a custom format binary file for the resources.
 */
public class StringResources {

  /**
   * Bump this whenever there's a change in the file format. The parser can decide to abort parsing
   * if the version it finds in the file does not match it's own version, thereby avoiding
   * potential data corruption issues.
   */
  private static final int FORMAT_VERSION = 1;

  public final TreeMap<Integer, String> strings;
  public final TreeMap<Integer, ImmutableMap<String, String>> plurals;
  public final TreeMultimap<Integer, String> arrays;

  /**
   * These are the 6 fixed plural categories for string resources in Android. This mapping is not
   * expected to change over time. We encode them as integers to optimize space.
   *
   * <p>For more information, refer to:
   * <a href="http://developer.android.com/guide/topics/resources/string-resource.html#Plurals">
   *   String Resources | Android Developers
   * </a></p>
   */
  private static final ImmutableMap<String, Integer> PLURAL_CATEGORY_MAP =
      ImmutableMap.<String, Integer>builder()
          .put("zero", 0)
          .put("one", 1)
          .put("two", 2)
          .put("few", 3)
          .put("many", 4)
          .put("other", 5)
          .build();

  private static Charset charset = Charsets.UTF_8;

  public StringResources(
      TreeMap<Integer, String> strings,
      TreeMap<Integer, ImmutableMap<String, String>> plurals,
      TreeMultimap<Integer, String> arrays) {
    this.strings = Preconditions.checkNotNull(strings);
    this.plurals = Preconditions.checkNotNull(plurals);
    this.arrays = Preconditions.checkNotNull(arrays);
  }

  public StringResources getMergedResources(StringResources otherResources) {
    TreeMap<Integer, String> stringsMap = Maps.newTreeMap(otherResources.strings);
    TreeMap<Integer, ImmutableMap<String, String>> pluralsMap =
        Maps.newTreeMap(otherResources.plurals);
    TreeMultimap<Integer, String> arraysMap = TreeMultimap.create(otherResources.arrays);

    stringsMap.putAll(strings);
    pluralsMap.putAll(plurals);
    arraysMap.putAll(arrays);

    return new StringResources(stringsMap, pluralsMap, arraysMap);
  }

  /**
   * Returns a byte array that represents the entire set of strings, plurals and string arrays in
   * the following binary file format:
   * <p>
   * <pre>
   *   [Int: Version]
   *   [Int: # of strings]
   *   [Int: Smallest resource id among strings]
   *   [Short: resource id delta][Short: length of the string] x # of strings
   *   [Byte array of the string value] x # of strings
   *   [Int: # of plurals]
   *   [Int: Smallest resource id among plurals]
   *   [[Short: resource id delta][Byte: #categories][[Byte: category][Short: length of plural
   *   value]] x #categories] x # of plurals
   *   [Byte array of plural value] x Summation of plural categories over # of plurals
   *   [Int: # of arrays]
   *   [Int: Smallest resource id among arrays]
   *   [[Short: resource id delta][Int: #elements][Short: length of element] x #elements] x # of
   *   arrays
   *   [Byte array of string value] x Summation of array elements over # of arrays
   * </pre>
   * </p>
   */
  public byte[] getBinaryFileContent() {
    try (
      ByteArrayOutputStream bytesStream = new ByteArrayOutputStream();
      DataOutputStream outputStream = new DataOutputStream(bytesStream)
    ) {
      outputStream.writeInt(FORMAT_VERSION);

      writeStrings(outputStream);
      writePlurals(outputStream);
      writeArrays(outputStream);

      return bytesStream.toByteArray();
    } catch (IOException e) {
      return null;
    }
  }

  private void writeStrings(DataOutputStream outputStream) throws IOException {
    outputStream.writeInt(strings.size());
    if (strings.isEmpty()) {
      return;
    }
    int previousResourceId = strings.firstKey();
    outputStream.writeInt(previousResourceId);

    try (ByteArrayOutputStream dataStream = new ByteArrayOutputStream()) {
      for (Map.Entry<Integer, String> entry : strings.entrySet()) {
        byte[] resourceBytes = entry.getValue().getBytes(charset);
        writeShort(outputStream, entry.getKey() - previousResourceId);
        writeShort(outputStream, resourceBytes.length);
        dataStream.write(resourceBytes, 0, resourceBytes.length);

        previousResourceId = entry.getKey();
      }
      outputStream.write(dataStream.toByteArray());
    }
  }

  private void writePlurals(DataOutputStream outputStream) throws IOException {
    outputStream.writeInt(plurals.size());
    if (plurals.isEmpty()) {
      return;
    }
    int previousResourceId = plurals.firstKey();
    outputStream.writeInt(previousResourceId);

    try (ByteArrayOutputStream dataStream = new ByteArrayOutputStream()) {
      for (Map.Entry<Integer, ImmutableMap<String, String>> entry : plurals.entrySet()) {
        writeShort(outputStream, entry.getKey() - previousResourceId);
        ImmutableMap<String, String> categoryMap = entry.getValue();
        outputStream.writeByte(categoryMap.size());

        for (Map.Entry<String, String> cat : categoryMap.entrySet()) {
          outputStream.writeByte(PLURAL_CATEGORY_MAP.get(cat.getKey()).byteValue());
          byte[] pluralValue = cat.getValue().getBytes(charset);
          writeShort(outputStream, pluralValue.length);
          dataStream.write(pluralValue);
        }

        previousResourceId = entry.getKey();
      }

      outputStream.write(dataStream.toByteArray());
    }
  }

  private void writeArrays(DataOutputStream outputStream) throws IOException {
    outputStream.writeInt(arrays.keySet().size());
    if (arrays.keySet().isEmpty()) {
      return;
    }
    int previousResourceId = arrays.keySet().first();
    outputStream.writeInt(previousResourceId);
    try (ByteArrayOutputStream dataStream = new ByteArrayOutputStream()) {
      for (int resourceId : arrays.keySet()) {
        writeShort(outputStream, resourceId - previousResourceId);
        Collection<String> arrayValues = arrays.get(resourceId);
        outputStream.writeInt(arrayValues.size());

        for (String arrayValue : arrayValues) {
          byte[] byteValue = arrayValue.getBytes(charset);
          writeShort(outputStream, byteValue.length);
          dataStream.write(byteValue);
        }

        previousResourceId = resourceId;
      }
      outputStream.write(dataStream.toByteArray());
    }
  }

  private void writeShort(DataOutputStream stream, int number) throws IOException {
    Preconditions.checkState(number <= Short.MAX_VALUE,
        "Error attempting to compact a numeral to short: " + number);
    stream.writeShort(number);
  }
}
