text: import Subset from './Subset';
  import CFFTop from '../cff/CFFTop';
  import CFFPrivateDict from '../cff/CFFPrivateDict';
  import standardStrings from '../cff/CFFStandardStrings';
  
  export default class CFFSubset extends Subset {
    constructor(font) {
      super(font);
  
      this.cff = this.font['CFF '];
      if (!this.cff) {
        throw new Error('Not a CFF Font');
      }
    }
  
    subsetCharstrings() {
      this.charstrings = [];
      let gsubrs = {};
  
      for (let gid of this.glyphs) {
        this.charstrings.push(this.cff.getCharString(gid));
  
        let glyph = this.font.getGlyph(gid);
        let path = glyph.path; // this causes the glyph to be parsed
  
        for (let subr in glyph._usedGsubrs) {
          gsubrs[subr] = true;
        }
      }
  
      this.gsubrs = this.subsetSubrs(this.cff.globalSubrIndex, gsubrs);
    }
  
    subsetSubrs(subrs, used) {
      let res = [];
      for (let i = 0; i < subrs.length; i++) {
        let subr = subrs[i];
        if (used[i]) {
          this.cff.stream.pos = subr.offset;
          res.push(this.cff.stream.readBuffer(subr.length));
        } else {
          res.push(Buffer.from([11])); // return
        }
      }
  
      return res;
    }
  
    subsetFontdict(topDict) {
      topDict.FDArray = [];
      topDict.FDSelect = {
        version: 0,
        fds: []
      };
  
      let used_fds = {};
      let used_subrs = [];
      for (let gid of this.glyphs) {
        let fd = this.cff.fdForGlyph(gid);
        if (fd == null) {
          continue;
        }
  
        if (!used_fds[fd]) {
          topDict.FDArray.push(Object.assign({}, this.cff.topDict.FDArray[fd]));
          used_subrs.push({});
        }
  
        used_fds[fd] = true;
        topDict.FDSelect.fds.push(topDict.FDArray.length - 1);
  
        let glyph = this.font.getGlyph(gid);
        let path = glyph.path; // this causes the glyph to be parsed
        for (let subr in glyph._usedSubrs) {
          used_subrs[used_subrs.length - 1][subr] = true;
        }
      }
  
      for (let i = 0; i < topDict.FDArray.length; i++) {
        let dict = topDict.FDArray[i];
        delete dict.FontName;
        if (dict.Private && dict.Private.Subrs) {
          dict.Private = Object.assign({}, dict.Private);
          dict.Private.Subrs = this.subsetSubrs(dict.Private.Subrs, used_subrs[i]);
        }
      }
  
      return;
    }
  
    createCIDFontdict(topDict) {
      let used_subrs = {};
      for (let gid of this.glyphs) {
        let glyph = this.font.getGlyph(gid);
        let path = glyph.path; // this causes the glyph to be parsed
  
        for (let subr in glyph._usedSubrs) {
          used_subrs[subr] = true;
        }
      }
  
      let privateDict = Object.assign({}, this.cff.topDict.Private);
      if (this.cff.topDict.Private && this.cff.topDict.Private.Subrs) {
        privateDict.Subrs = this.subsetSubrs(this.cff.topDict.Private.Subrs, used_subrs);
      }
  
      topDict.FDArray = [{ Private: privateDict }];
      return topDict.FDSelect = {
        version: 3,
        nRanges: 1,
        ranges: [{ first: 0, fd: 0 }],
        sentinel: this.charstrings.length
      };
    }
  
    addString(string) {
      if (!string) {
        return null;
      }
  
      if (!this.strings) {
        this.strings = [];
      }
  
      this.strings.push(string);
      return standardStrings.length + this.strings.length - 1;
    }
  
    encode(stream) {
      this.subsetCharstrings();
  
      let charset = {
        version: this.charstrings.length > 255 ? 2 : 1,
        ranges: [{ first: 1, nLeft: this.charstrings.length - 2 }]
      };
  
      let topDict = Object.assign({}, this.cff.topDict);
      topDict.Private = null;
      topDict.charset = charset;
      topDict.Encoding = null;
      topDict.CharStrings = this.charstrings;
  
      for (let key of ['version', 'Notice', 'Copyright', 'FullName', 'FamilyName', 'Weight', 'PostScript', 'BaseFontName', 'FontName']) {
        topDict[key] = this.addString(this.cff.string(topDict[key]));
      }
  
      topDict.ROS = [this.addString('Adobe'), this.addString('Identity'), 0];
      topDict.CIDCount = this.charstrings.length;
  
      if (this.cff.isCIDFont) {
        this.subsetFontdict(topDict);
      } else {
        this.createCIDFontdict(topDict);
      }
  
      let top = {
        version: 1,
        hdrSize: this.cff.hdrSize,
        offSize: 4,
        header: this.cff.header,
        nameIndex: [this.cff.postscriptName],
        topDictIndex: [topDict],
        stringIndex: this.strings,
        globalSubrIndex: this.gsubrs
      };
  
      CFFTop.encode(stream, top);
    }
  }
  