// Copyright 2014 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
// Original code is licensed as follows:
/*
 * Copyright 2010 ZXing authors
 *
 * 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 "fxbarcode/oned/BC_OnedCode39Writer.h"

#include <algorithm>
#include <array>
#include <iterator>
#include <memory>

#include "core/fxcrt/compiler_specific.h"
#include "core/fxcrt/fx_extension.h"
#include "fxbarcode/BC_Writer.h"
#include "fxbarcode/oned/BC_OneDimWriter.h"

namespace {

constexpr auto kOnedCode39Alphabet = std::to_array<const char>(
    {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
     'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
     'U', 'V', 'W', 'X', 'Y', 'Z', '-', '.', ' ', '*', '$', '/', '+', '%'});
constexpr size_t kOnedCode39AlphabetLen = std::size(kOnedCode39Alphabet);

constexpr auto kOnedCode39Checksum = std::to_array<const char>(
    {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
     'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
     'U', 'V', 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%'});
static_assert(std::size(kOnedCode39Checksum) == 43, "Wrong size");

constexpr auto kOnedCode39CharacterEncoding = std::to_array<const uint16_t>(
    {0x0034, 0x0121, 0x0061, 0x0160, 0x0031, 0x0130, 0x0070, 0x0025, 0x0124,
     0x0064, 0x0109, 0x0049, 0x0148, 0x0019, 0x0118, 0x0058, 0x000D, 0x010C,
     0x004C, 0x001C, 0x0103, 0x0043, 0x0142, 0x0013, 0x0112, 0x0052, 0x0007,
     0x0106, 0x0046, 0x0016, 0x0181, 0x00C1, 0x01C0, 0x0091, 0x0190, 0x00D0,
     0x0085, 0x0184, 0x00C4, 0x0094, 0x00A8, 0x00A2, 0x008A, 0x002A});
static_assert(std::size(kOnedCode39CharacterEncoding) == 44, "Wrong size");

bool IsInOnedCode39Alphabet(wchar_t ch) {
  return FXSYS_IsDecimalDigit(ch) || (ch >= L'A' && ch <= L'Z') || ch == L'-' ||
         ch == L'.' || ch == L' ' || ch == L'*' || ch == L'$' || ch == L'/' ||
         ch == L'+' || ch == L'%';
}

char CalcCheckSum(const ByteString& contents) {
  if (contents.GetLength() > 80) {
    return '*';
  }

  int32_t checksum = 0;
  for (const auto& c : contents) {
    size_t j = 0;
    for (; j < kOnedCode39AlphabetLen; j++) {
      if (kOnedCode39Alphabet[j] == c) {
        if (c != '*') {
          checksum += j;
        }
        break;
      }
    }
    if (j >= kOnedCode39AlphabetLen) {
      return '*';
    }
  }
  return kOnedCode39Checksum[checksum % std::size(kOnedCode39Checksum)];
}

void ToIntArray(int16_t value, uint8_t ratio, pdfium::span<uint8_t> span) {
  for (size_t i = 0; i < span.size(); i++) {
    span[i] = (value & (1 << i)) == 0 ? 1 : ratio;
  }
}

}  // namespace

CBC_OnedCode39Writer::CBC_OnedCode39Writer() = default;

CBC_OnedCode39Writer::~CBC_OnedCode39Writer() = default;

bool CBC_OnedCode39Writer::CheckContentValidity(WideStringView contents) {
  return HasValidContentSize(contents) &&
         std::all_of(contents.begin(), contents.end(), IsInOnedCode39Alphabet);
}

WideString CBC_OnedCode39Writer::FilterContents(WideStringView contents) {
  WideString filtercontents;
  filtercontents.Reserve(contents.GetLength());
  for (size_t i = 0; i < contents.GetLength(); i++) {
    wchar_t ch = contents[i];
    if (ch == L'*' && (i == 0 || i == contents.GetLength() - 1)) {
      continue;
    }
    if (ch > 175) {
      i++;
      continue;
    }
    ch = FXSYS_ToUpperASCII(ch);
    if (IsInOnedCode39Alphabet(ch)) {
      filtercontents += ch;
    }
  }
  return filtercontents;
}

WideString CBC_OnedCode39Writer::RenderTextContents(WideStringView contents) {
  WideString renderContents;
  for (size_t i = 0; i < contents.GetLength(); i++) {
    wchar_t ch = contents[i];
    if (ch == L'*' && (i == 0 || i == contents.GetLength() - 1)) {
      continue;
    }
    if (ch > 175) {
      i++;
      continue;
    }
    if (IsInOnedCode39Alphabet(FXSYS_ToUpperASCII(ch))) {
      renderContents += ch;
    }
  }
  return renderContents;
}

void CBC_OnedCode39Writer::SetTextLocation(BC_TEXT_LOC location) {
  loc_text_loc_ = location;
}

bool CBC_OnedCode39Writer::SetWideNarrowRatio(int8_t ratio) {
  if (ratio < 2 || ratio > 3) {
    return false;
  }

  wide_narr_ratio_ = ratio;
  return true;
}

DataVector<uint8_t> CBC_OnedCode39Writer::Encode(const ByteString& contents) {
  char checksum = CalcCheckSum(contents);
  if (checksum == '*') {
    return DataVector<uint8_t>();
  }

  std::array<uint8_t, kArraySize> widths = {};
  static constexpr int32_t kWideStrideNum = 3;
  static constexpr int32_t kNarrowStrideNum = kArraySize - kWideStrideNum;
  ByteString encodedContents = contents;
  if (calc_checksum_) {
    encodedContents += checksum;
  }
  content_len_ = encodedContents.GetLength();
  size_t code_width =
      (kWideStrideNum * wide_narr_ratio_ + kNarrowStrideNum) * 2 + 1 +
      content_len_;
  for (size_t j = 0; j < content_len_; j++) {
    for (size_t i = 0; i < kOnedCode39AlphabetLen; i++) {
      if (kOnedCode39Alphabet[i] != encodedContents[j]) {
        continue;
      }
      ToIntArray(kOnedCode39CharacterEncoding[i], wide_narr_ratio_, widths);
      for (size_t k = 0; k < kArraySize; k++) {
        code_width += widths[k];
      }
    }
  }
  DataVector<uint8_t> result(code_width);
  auto result_span = pdfium::span(result);
  ToIntArray(kOnedCode39CharacterEncoding[39], wide_narr_ratio_, widths);
  result_span = AppendPattern(result_span, widths, true);

  static constexpr uint8_t kNarrowWhite[] = {1};
  result_span = AppendPattern(result_span, kNarrowWhite, false);

  for (int32_t l = content_len_ - 1; l >= 0; l--) {
    for (size_t i = 0; i < kOnedCode39AlphabetLen; i++) {
      if (kOnedCode39Alphabet[i] != encodedContents[l]) {
        continue;
      }
      ToIntArray(kOnedCode39CharacterEncoding[i], wide_narr_ratio_, widths);
      result_span = AppendPattern(result_span, widths, true);
    }
    result_span = AppendPattern(result_span, kNarrowWhite, false);
  }
  ToIntArray(kOnedCode39CharacterEncoding[39], wide_narr_ratio_, widths);
  AppendPattern(result_span, widths, true);

  for (size_t i = 0; i < code_width / 2; i++) {
    result[i] ^= result[code_width - 1 - i];
    result[code_width - 1 - i] ^= result[i];
    result[i] ^= result[code_width - 1 - i];
  }
  return result;
}

bool CBC_OnedCode39Writer::encodedContents(WideStringView contents,
                                           WideString* result) {
  *result = WideString(contents);
  if (calc_checksum_ && print_checksum_) {
    WideString checksumContent = FilterContents(contents);
    ByteString str = checksumContent.ToUTF8();
    char checksum;
    checksum = CalcCheckSum(str);
    if (checksum == '*') {
      return false;
    }
    str += checksum;
    *result += checksum;
  }
  return true;
}

bool CBC_OnedCode39Writer::RenderResult(WideStringView contents,
                                        pdfium::span<const uint8_t> code) {
  WideString encodedCon;
  if (!encodedContents(contents, &encodedCon)) {
    return false;
  }
  return CBC_OneDimWriter::RenderResult(encodedCon.AsStringView(), code);
}
