import {
  fromUtf8CodePoint,
  utf8Length as $utf8Length
} from "@thi.ng/strings/utf8";
import { compR } from "@thi.ng/transducers/compr";
import { iterator, iterator1 } from "@thi.ng/transducers/iterator";
import { isReduced } from "@thi.ng/transducers/reduced";
function utf8Decode(src) {
  return src ? [...iterator1(utf8Decode(), src)].join("") : (rfn) => {
    const r = rfn[2];
    let state = 0;
    let u0;
    let u1;
    let u2;
    let u3;
    let u4;
    return compR(rfn, (acc, x) => {
      switch (state) {
        case 0:
        default:
          if (x < 128) {
            return r(acc, String.fromCharCode(x));
          }
          u0 = x;
          state = 1;
          break;
        case 1:
          u1 = x & 63;
          if ((u0 & 224) === 192) {
            state = 0;
            return r(
              acc,
              String.fromCharCode((u0 & 31) << 6 | u1)
            );
          }
          state = 2;
          break;
        case 2:
          u2 = x & 63;
          if ((u0 & 240) === 224) {
            state = 0;
            return r(
              acc,
              String.fromCharCode(
                (u0 & 15) << 12 | u1 << 6 | u2
              )
            );
          }
          state = 3;
          break;
        case 3:
          u3 = x & 63;
          if ((u0 & 248) === 240) {
            state = 0;
            return r(
              acc,
              fromUtf8CodePoint(
                (u0 & 7) << 18 | u1 << 12 | u2 << 6 | u3
              )
            );
          }
          state = 4;
          break;
        case 4:
          u4 = x & 63;
          if ((u0 & 252) === 248) {
            state = 0;
            return r(
              acc,
              fromUtf8CodePoint(
                (u0 & 3) << 24 | u1 << 18 | u2 << 12 | u3 << 6 | u4
              )
            );
          }
          state = 5;
          break;
        case 5:
          state = 0;
          return r(
            acc,
            fromUtf8CodePoint(
              (u0 & 1) << 30 | u1 << 24 | u2 << 18 | u3 << 12 | u4 << 6 | x & 63
            )
          );
      }
      return acc;
    });
  };
}
function utf8Encode(src) {
  return src != null ? new Uint8Array(iterator(utf8Encode(), src)) : (rfn) => {
    const r = rfn[2];
    return compR(rfn, (acc, x) => {
      let u = x.charCodeAt(0), buf;
      if (u >= 55296 && u <= 57343) {
        u = 65536 + ((u & 1023) << 10) | x.charCodeAt(1) & 1023;
      }
      if (u < 128) {
        return r(acc, u);
      } else if (u < 2048) {
        buf = [192 | u >> 6, 128 | u & 63];
      } else if (u < 65536) {
        buf = [
          224 | u >> 12,
          128 | u >> 6 & 63,
          128 | u & 63
        ];
      } else if (u < 2097152) {
        buf = [
          240 | u >> 18,
          128 | u >> 12 & 63,
          128 | u >> 6 & 63,
          128 | u & 63
        ];
      } else if (u < 67108864) {
        buf = [
          248 | u >> 24,
          128 | u >> 18 & 63,
          128 | u >> 12 & 63,
          128 | u >> 6 & 63,
          128 | u & 63
        ];
      } else {
        buf = [
          252 | u >> 30,
          128 | u >> 24 & 63,
          128 | u >> 18 & 63,
          128 | u >> 12 & 63,
          128 | u >> 6 & 63,
          128 | u & 63
        ];
      }
      for (let i = 0, n = buf.length; i < n; i++) {
        acc = r(acc, buf[i]);
        if (isReduced(acc)) {
          break;
        }
      }
      return acc;
    });
  };
}
const utf8Length = $utf8Length;
export {
  utf8Decode,
  utf8Encode,
  utf8Length
};
