/*
 * Copyright 2011 Google Inc. All Rights Reserved.
 *
 * 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.
 */

#include <stdio.h>

#include <vector>
#include <string>
#include <sstream>

#include "sfntly/port/type.h"
#include "font_subsetter.h"

template <typename T>
class HexTo {
 public:
  explicit HexTo(const char* in) {
    std::stringstream ss;
    ss << std::hex << in;
    ss >> value_;
  }
  operator T() const { return value_; }

 private:
  T value_;
};

bool LoadFile(const char* input_file_path, sfntly::ByteVector* input_buffer) {
  assert(input_file_path);
  assert(input_buffer);

  FILE* input_file = NULL;
#if defined WIN32
  fopen_s(&input_file, input_file_path, "rb");
#else
  input_file = fopen(input_file_path, "rb");
#endif
  if (input_file == NULL) {
    return false;
  }
  fseek(input_file, 0, SEEK_END);
  size_t file_size = ftell(input_file);
  fseek(input_file, 0, SEEK_SET);
  input_buffer->resize(file_size);
  size_t bytes_read = fread(&((*input_buffer)[0]), 1, file_size, input_file);
  fclose(input_file);
  return bytes_read == file_size;
}

bool SaveFile(const char* output_file_path, const unsigned char* output_buffer,
              int buffer_length) {
  int byte_count = 0;
  if (buffer_length > 0) {
    FILE* output_file = NULL;
#if defined WIN32
    fopen_s(&output_file, output_file_path, "wb");
#else
    output_file = fopen(output_file_path, "wb");
#endif
    if (output_file) {
      byte_count = fwrite(output_buffer, 1, buffer_length, output_file);
      fflush(output_file);
      fclose(output_file);
    }
    return buffer_length == byte_count;
  }
  return false;
}

bool StringToGlyphId(const char* input, std::vector<unsigned int>* glyph_ids) {
  assert(input);
  std::string hex_csv = input;
  size_t start = 0;
  size_t end = hex_csv.find_first_of(",");
  while (end != std::string::npos) {
    glyph_ids->push_back(
        HexTo<unsigned int>(hex_csv.substr(start, end - start).c_str()));
    start = end + 1;
    end = hex_csv.find_first_of(",", start);
  }
  glyph_ids->push_back(HexTo<unsigned int>(hex_csv.substr(start).c_str()));
  return glyph_ids->size() > 0;
}

int main(int argc, char** argv) {
  if (argc < 5) {
    fprintf(stderr,
        "Usage: %s <input path> <output path> <font name> <glyph ids>\n",
        argv[0]);
    fprintf(stderr, "\tGlyph ids are comma separated hex values\n");
    fprintf(stderr, "\te.g. 20,1a,3b,4f\n");
    return 0;
  }

  sfntly::ByteVector input_buffer;
  if (!LoadFile(argv[1], &input_buffer)) {
    fprintf(stderr, "ERROR: unable to load font file %s\n", argv[1]);
    return 0;
  }

  std::vector<unsigned int> glyph_ids;
  if (!StringToGlyphId(argv[4], &glyph_ids)) {
    fprintf(stderr, "ERROR: unable to parse input glyph id\n");
    return 0;
  }

  unsigned char* output_buffer = NULL;
  int output_length =
      SfntlyWrapper::SubsetFont(argv[3],
                                &(input_buffer[0]),
                                input_buffer.size(),
                                &(glyph_ids[0]),
                                glyph_ids.size(),
                                &output_buffer);

  int result = SaveFile(argv[2], output_buffer, output_length) ? 1 : 0;
  delete[] output_buffer;
  return result;
}