"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _speedDate = require("speed-date");

var _core = require("@kui-shell/core");

var _usageHelpers = require("./usage-helpers");

/*
 * Copyright 2018-19 IBM Corporation
 *
 * 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.
 */
var __awaiter = void 0 && (void 0).__awaiter || function (thisArg, _arguments, P, generator) {
  function adopt(value) {
    return value instanceof P ? value : new P(function (resolve) {
      resolve(value);
    });
  }

  return new (P || (P = Promise))(function (resolve, reject) {
    function fulfilled(value) {
      try {
        step(generator.next(value));
      } catch (e) {
        reject(e);
      }
    }

    function rejected(value) {
      try {
        step(generator["throw"](value));
      } catch (e) {
        reject(e);
      }
    }

    function step(result) {
      result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
    }

    step((generator = generator.apply(thisArg, _arguments || [])).next());
  });
};

const dateFormatter = (0, _speedDate.UTC)('MMM DD HH:mm');
const strings = (0, _core.i18n)('plugin-bash-like');
/**
 * Mimic ls -lh
 *
 */

function prettyBytes(size) {
  if (size < 1024) {
    return `${size}B`;
  } else if (size < 1024 * 1024) {
    return `${(size / 1024).toFixed(1)}K`;
  } else if (size < 1024 * 1024 * 1024) {
    return `${(size / 1024 / 1024).toFixed(1)}M`;
  } else if (size < 1024 * 1024 * 1024 * 1024) {
    return `${(size / 1024 / 1024 / 1024).toFixed(1)}G`;
  } else {
    return `${(size / 1024 / 1024 / 1024 / 1024).toFixed(1)}T`;
  }
}
/**
 * Mimic ls -l for date
 *
 */


function prettyTime(ms) {
  // if we ever want to re-introduce i18n of ls dates; this will be
  // about 100x slower; see https://github.com/IBM/kui/issues/3461

  /* return new Date(ms).toLocaleString(navigator.language, {
    month: 'short', day: '2-digit', hour: '2-digit', 'minute': '2-digit', hour12: false
    }).replace(/(\s)0/g, '$1 ').replace(/,/g, '') */
  // warning: this will generate (very quickly) not-internationalized
  // ls dates
  return dateFormatter(new Date(ms)).replace(/(\s)0/g, '$1 ');
}
/** sort by size */


const bySize = rev => (a, b) => {
  return rev * (b.stats.size - a.stats.size);
};
/** sort by last modification time */


const byTime = rev => (a, b) => {
  return rev * (b.stats.mtimeMs - a.stats.mtimeMs);
};
/** sort lexicographically by name */


const byLex = rev => (a, b) => {
  return rev * a.nameForDisplay.localeCompare(b.nameForDisplay);
};
/**
 * Decorate an entry according to its nature
 *
 */


function cssOf(glob) {
  const {
    isDirectory,
    isSymbolicLink,
    isExecutable,
    isSpecial
  } = glob.dirent;
  return isDirectory ? 'dir-listing-is-directory' : isSymbolicLink ? 'dir-listing-is-link' : isExecutable ? 'dir-listing-is-executable' : isSpecial ? 'dir-listing-is-other-special' : '';
}
/**
 * Decorate the name according to its nature
 *
 */


function nameOf(glob) {
  return `${glob.nameForDisplay}${glob.dirent.isDirectory ? !glob.nameForDisplay.endsWith('/') ? '/' : '' : glob.dirent.isSymbolicLink ? '@' : glob.dirent.isExecutable ? '*' : ''}`;
}

const outerCSSSecondary = 'hide-with-sidecar';
const cssSecondary = 'slightly-deemphasize';
const outerCSSLesser = 'hide-with-narrow-window';
const cssLesser = 'elide-with-narrow-window';

function formatPermissions({
  dirent
}) {
  return dirent.permissions;
}

function formatUid(entry) {
  return entry.dirent.username || entry.stats.uid.toString();
}

function formatGid(entry) {
  return entry.stats.gid.toString();
}

function attrs(entry, args) {
  // const language = withLanguage(args.execOptions).language
  const wide = args.parsedOptions.l;
  const perms = wide ? [{
    value: formatPermissions(entry),
    outerCSS: outerCSSSecondary
  }] : [];
  const uid = wide ? [{
    value: formatUid(entry),
    outerCSS: outerCSSSecondary,
    css: cssSecondary
  }] : [];
  const gid = wide ? [{
    value: formatGid(entry),
    outerCSS: outerCSSSecondary,
    css: cssSecondary
  }] : [];
  const size = wide ? [{
    value: prettyBytes(entry.stats.size).replace(/\s/g, ''),
    outerCSS: `${outerCSSSecondary} text-right`
  }] : [];
  const lastMod = wide ? [{
    value: prettyTime(entry.stats.mtimeMs),
    outerCSS: outerCSSLesser,
    css: `${cssLesser} ${cssSecondary} pre-wrap`
  }] : [];
  return perms.concat(uid).concat(gid).concat(size).concat(lastMod);
}
/**
 * Turn an array of glob results into a Kui Table
 *
 */


function toTable(entries, args) {
  const rev = args.parsedOptions.r ? -1 : 1;
  const sorter = args.parsedOptions.S ? bySize(rev) : args.parsedOptions.t ? byTime(rev) : byLex(rev);
  const body = entries.sort(sorter).map(_ => ({
    name: nameOf(_),
    css: cssOf(_),
    onclickExec: 'pexec',
    onclick: `${_.dirent.isDirectory ? 'ls' : 'open'} ${args.REPL.encodeComponent(_.path)}`,
    attributes: attrs(_, args)
  }));

  if (!args.parsedOptions.l) {
    const frag = document.createDocumentFragment();
    body.forEach(_ => {
      const cell = document.createElement('div');
      cell.innerText = _.name;

      if (_.css) {
        cell.classList.add(_.css);
      }

      cell.classList.add('clickable');

      cell.onclick = () => args.REPL.pexec(_.onclick);

      frag.appendChild(cell);
    });
    const container = document.createElement('div');
    container.classList.add('grid-layout');
    container.appendChild(frag);
    return container;
  } else {
    const perms = [{
      value: 'PERMISSIONS',
      outerCSS: outerCSSSecondary
    }];
    const uid = [{
      value: 'USER',
      outerCSS: outerCSSSecondary
    }];
    const gid = [{
      value: 'GROUP',
      outerCSS: outerCSSSecondary
    }];
    const size = [{
      value: 'SIZE',
      outerCSS: `${outerCSSSecondary} text-right`
    }];
    const lastMod = [{
      value: 'LAST MODIFIED',
      outerCSS: outerCSSLesser,
      css: cssLesser
    }];
    const header = {
      name: 'NAME',
      attributes: perms.concat(uid).concat(gid).concat(size).concat(lastMod)
    };
    return {
      header,
      body,
      noSort: true,
      noEntityColors: true,
      style: _core.TableStyle.Light
    };
  }
}
/**
 * ls command handler
 *
 */


const doLs = cmd => opts => __awaiter(void 0, void 0, void 0, function* () {
  const semi = yield opts.REPL.semicolonInvoke(opts);

  if (semi) {
    return semi;
  } else if (/\|/.test(opts.command)) {
    // conservatively send possibly piped output to the PTY
    return opts.REPL.qexec(`sendtopty ${opts.command}`, opts.block);
  }

  if (cmd === 'lls') {
    opts.parsedOptions.l = true;
  }

  const entries = (yield opts.REPL.rexec(`kuiglob ${opts.argvNoOptions.slice(opts.argvNoOptions.indexOf(cmd) + 1).map(_ => opts.REPL.encodeComponent(_)).join(' ')} ${opts.parsedOptions.l ? '-l' : ''} ${opts.parsedOptions.C ? '-C' : ''} ${opts.parsedOptions.a || opts.parsedOptions.all || opts.parsedOptions.A ? '-a' : ''} ${opts.parsedOptions.d ? '-d' : ''}`)).content;
  return toTable(entries, opts);
});

const usage = command => ({
  command,
  title: strings('lsUsageTitle'),
  header: strings('lsUsageHeader'),
  noHelpAlias: true,
  optional: _usageHelpers.localFilepath.concat([{
    name: '-A',
    boolean: true,
    docs: strings('lsDashAUsageDocs')
  }, {
    name: '-a',
    boolean: true,
    docs: strings('lsDashaUsageDocs')
  }, {
    name: '-d',
    boolean: true,
    docs: strings('lsDashdUsageDocs')
  }, {
    name: '-c',
    boolean: true,
    docs: strings('lsDashcUsageDocs')
  }, {
    name: '-C',
    boolean: true,
    hidden: true
  }, {
    name: '-l',
    boolean: true,
    hidden: true
  }, {
    name: '-h',
    boolean: true,
    hidden: true
  }, {
    name: '-t',
    boolean: true,
    docs: strings('lsDashtUsageDocs')
  }, {
    name: '-r',
    boolean: true,
    docs: strings('lsDashrUsageDocs')
  }, {
    name: '-s',
    boolean: true,
    hidden: true
  }, {
    name: '-S',
    boolean: true,
    docs: strings('lsDashSUsageDocs')
  }])
});
/**
 * Register command handlers
 *
 */


var _default = commandTree => {
  const ls = commandTree.listen('/ls', doLs('ls'), {
    usage: usage('ls'),
    flags: {
      boolean: usage('ls').optional.filter(_ => _.boolean).map(_ => _.name.replace(/^-(-)?/, ''))
    }
  });
  commandTree.synonym('/lls', doLs('lls'), ls, {
    usage: usage('lls')
  });
};

exports.default = _default;