"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.doGetAsTable = doGetAsTable;
exports.doGetAsEntity = doGetAsEntity;
exports.doGetAsMMR = doGetAsMMR;
exports.rawGet = rawGet;
exports.viewTransformer = viewTransformer;
exports.getter = getter;
exports.default = exports.getFlags = exports.doGet = void 0;

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

var _flags = _interopRequireDefault(require("./flags"));

var _exec = require("./exec");

var _explain = require("./explain");

var _fqn = require("./fqn");

var _commandPrefix = _interopRequireDefault(require("../command-prefix"));

var _getWatch = _interopRequireDefault(require("./watch/get-watch"));

var _name = _interopRequireDefault(require("../../lib/util/name"));

var _help = require("../../lib/util/help");

var _options = require("./options");

var _formatTable = require("../../lib/view/formatTable");

var _resource = require("../../lib/model/resource");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/*
 * Copyright 2019-2020 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 strings = (0, _core.i18n)('plugin-kubectl');
/**
 * For now, we handle watch ourselves, so strip these options off the command line
 *
 */

function prepareArgsForGet(args) {
  const stripThese = ['-w=true', '--watch=true', '--watch-only=true', '-w', '--watch', '--watch-only'];
  const idx = args.command.indexOf(' get ') + ' get '.length;
  const pre = args.command.slice(0, idx - 1);
  const post = args.command.slice(idx - 1);
  return pre + stripThese.reduce((cmd, strip) => cmd.replace(new RegExp(`(\\s)${strip}`), '$1'), post);
}
/**
 * `kubectl get` as a table response
 *
 */


function doGetAsTable(command, args, response, verb = 'get', fullKind) {
  const {
    content: {
      stderr,
      stdout
    }
  } = response;
  const entityType = fullKind || args.argvNoOptions[args.argvNoOptions.indexOf(verb) + 1];
  return (0, _formatTable.stringToTable)(stdout, stderr, args, command, verb, entityType);
}
/**
 * `kubectl get --watch` as a table response, but for the special case
 * where there is nothing yet to display
 *
 */

/* function doGetEmptyWatchTable(args: Arguments<KubeOptions>): KubeTableResponse {
  const emptyTable = { body: [] }
  return initWatch(args, emptyTable)
} */

/**
 * `kubectl get` as entity response
 *
 */


function doGetAsEntity(args, response) {
  return __awaiter(this, void 0, void 0, function* () {
    try {
      // this is the raw data string we get from `kubectl`
      const data = response.content.stdout; // parse the raw response; the parser we use depends on whether
      // the user asked for JSON or for YAML

      const resource = (0, _options.formatOf)(args) === 'json' ? JSON.parse(data) : (yield Promise.resolve().then(() => require('js-yaml'))).safeLoad(data);
      const kuiResponse = Object.assign(resource, {
        isKubeResource: true,
        kuiRawData: data
      });

      if ((0, _resource.isKubeItems)(kuiResponse)) {
        // so that isPod() etc. work on the items
        kuiResponse.items.forEach(_ => _.isKubeResource = true);
      }

      return kuiResponse;
    } catch (err) {
      console.error('error handling entity response; raw=', response.content.stdout);
      throw err;
    }
  });
}
/** Pretty-print creationTimestamp */


function creationTimestamp(resource) {
  return new Date(resource.metadata.creationTimestamp).toLocaleString();
}
/** ToolbarText presentation */


function toolbarText(resource) {
  const type = 'info';
  const hasTimestamp = resource.metadata.creationTimestamp !== undefined;
  const hasVersion = (0, _resource.hasResourceVersion)(resource);

  if (hasTimestamp && hasVersion) {
    return {
      type,
      text: strings('createdOn=X resourceVersion=Y', creationTimestamp(resource), resource.metadata.resourceVersion)
    };
  } else if (hasTimestamp) {
    return {
      type,
      text: strings('createdOn', creationTimestamp(resource))
    };
  } else if (hasVersion) {
    return {
      type,
      text: strings('resourceVersion=Y', creationTimestamp(resource), resource.metadata.resourceVersion)
    };
  }
}
/**
 * `kubectl get` as entity response
 *
 */


function doGetAsMMR(args, resource) {
  return __awaiter(this, void 0, void 0, function* () {
    try {
      // attempt to separate out the app and generated parts of the resource name
      const {
        name: prettyName,
        nameHash,
        version
      } = (0, _name.default)(resource);

      if ((0, _resource.isKubeItems)(resource)) {
        // then this is a response to e.g. `kubectl get pods -o yaml`
        return {
          apiVersion: resource.apiVersion,
          kind: resource.kind,
          metadata: {
            name: args.command,
            namespace: yield (0, _options.getNamespace)(args)
          },
          isSimulacrum: true,
          originatingCommand: args.command,
          isKubeResource: true,
          modes: [],
          kuiRawData: resource.kuiRawData
        };
      }

      return Object.assign(resource, {
        prettyName,
        nameHash,
        version,
        comparator: _resource.sameResourceVersion,
        originatingCommand: args.command,
        isKubeResource: true,
        toolbarText: toolbarText(resource),
        onclick: {
          kind: `kubectl get ${(0, _fqn.kindAndNamespaceOf)(resource)}`,
          name: `kubectl get ${(0, _fqn.kindAndNamespaceOf)(resource)} ${resource.metadata.name}`,
          namespace: resource.metadata.namespace ? `kubectl get ns ${resource.metadata.namespace} -o yaml` : undefined
        },
        modes: [],
        kuiRawData: resource.kuiRawData // also include the raw, uninterpreted data string we got back

      });
    } catch (err) {
      console.error('error handling entity response', resource);
      throw err;
    }
  });
}
/**
 * kubectl get as custom response
 *
 */


function doGetCustom(args, response) {
  return __awaiter(this, void 0, void 0, function* () {
    return response.content.stdout.trim();
  });
}

function rawGet(args, _command = 'kubectl') {
  const command = _command === 'k' ? 'kubectl' : _command;
  return (0, _exec.exec)(args, prepareArgsForGet, command).catch(err => {
    // Notes: we are using statusCode internally to this plugin;
    // delete it before rethrowing the error, because the core would
    // otherwise interpret the statusCode as being meaningful to the
    // outside world
    delete err.statusCode; // trim? at least with 1.15 clients, e.g. `kubectl get all -l
    // app=foo` emits weird initial blank newlines

    err.message = err.message.trim();
    throw err;
  });
}
/**
 *  Force Event Watcher to show the NAME column with Event ID
 *  This helps kui table watcher to distinguish the updated rows
 *
 */


const overrideEventCommand = (args, output) => {
  if (output) {
    const cmd = args.command.replace(`${args.parsedOptions.o ? '-o' : '--output'} ${output}`, '-o wide');
    return args.REPL.qexec(cmd);
  } else {
    const cmd = `${args.command} -o wide`;
    return args.REPL.qexec(cmd);
  }
};
/**
 * This is the main handler for `kubectl get`. Here, we act as a
 * dispatcher: in `kubectl` a `get` can mean either get-as-table,
 * get-as-entity, or get-as-custom, depending on the `-o` flag.
 *
 */


const doGet = command => function doGet(args) {
  return __awaiter(this, void 0, void 0, function* () {
    // first, peel off some special cases:
    if ((0, _help.isUsage)(args)) {
      // special case: get --help/-h
      return (0, _help.doHelp)(command, args, prepareArgsForGet);
    } // first, we do the raw exec of the given command


    const isTableReq = (0, _options.isTableRequest)(args);
    const fullKind = isTableReq ? (0, _explain.getKind)(command, args, args.argvNoOptions[args.argvNoOptions.indexOf('get') + 1]) : undefined;

    if (!(0, _core.isHeadless)() && (0, _options.isWatchRequest)(args)) {
      // special case: get --watch/watch-only
      // special case of special case: kubectl -w get fails; even
      // though we could handle it, we have decided to keep parity
      // with kubectl's errors here
      if (!/^k(ubectl)?\s+-/.test(args.command)) {
        const output = args.parsedOptions.o || args.parsedOptions.output;

        if ((yield fullKind) === 'Event' && output !== 'wide') {
          return overrideEventCommand(args, output);
        } else {
          return (0, _getWatch.default)(args);
        }
      }
    }

    const response = yield rawGet(args, command);

    if ((0, _formatTable.isKubeTableResponse)(response)) {
      return response;
    } else if (response.content.code !== 0 && !isTableReq && response.content.stdout.length === 0) {
      // raw exec yielded an error!
      const err = new Error(response.content.stderr);
      err.code = response.content.code;
      throw err;
    } else if (response.content.wasSentToPty) {
      return response.content.stdout;
    } else if ((0, _options.isEntityRequest)(args)) {
      // case 1: get-as-entity
      return doGetAsEntity(args, response);
    } else if (isTableReq) {
      // case 2: get-as-table
      return doGetAsTable(command, args, response, undefined, yield fullKind);
    } else {
      // case 3: get-as-custom
      return doGetCustom(args, response);
    }
  });
};
/** KubeResource -> MultiModalResponse view transformer */


exports.doGet = doGet;

function viewTransformer(args, response) {
  if ((0, _resource.isKubeResource)(response)) {
    return doGetAsMMR(args, response);
  }
}

const getFlags = Object.assign({}, _flags.default, {
  viewTransformer
});
/** Register a command listener */

exports.getFlags = getFlags;

function getter(registrar, command, cli = command) {
  registrar.listen(`/${_commandPrefix.default}/${command}/get`, doGet(cli), getFlags);
}

var _default = registrar => {
  getter(registrar, 'kubectl');
  getter(registrar, 'k', 'kubectl');
};

exports.default = _default;