/**
 *
 * This represents a formula supported under SQL for on-demand tables.  This is currently
 * a very small subset of the formulas supported by the data engine for regular tables.
 *
 * The following kinds of formula are supported:
 *   $refColId.colId    [where colId is not itself a formula]
 *   $colId             [where colId is not itself a formula]
 *   NNN                [a non-negative integer]
 * TODO: support a broader range of formula, by adding a parser or reusing Python parser.
 * An argument for reusing Python parser: wwe already do substantial parsing of the formula code.
 * E.g. Python does such amazing things as handle updating the formula when any of the columns
 * referred to in Foo.lookup(bar=$baz).blah get updated.
 *
 */
export type Formula = LiteralNumberFormula | ColumnFormula | ForeignColumnFormula | FormulaError;

// A simple copy of another column.  E.g. "$Person"
export interface ColumnFormula {
  kind: 'column';
  colId: string;
}

// A copy of a column in another table (via a reference column).  E.g. "$Person.FirstName"
export interface ForeignColumnFormula {
  kind: 'foreignColumn';
  colId: string;
  refColId: string;
}

export interface LiteralNumberFormula {
  kind: 'literalNumber';
  value: number;
}

// A formula that couldn't be parsed.
export interface FormulaError {
  kind: 'error';
  msg: string;
}

/**
 * Convert a string to a parsed formula.  Regexes are adequate for the very few
 * supported formulas, but once the syntax is at all flexible a proper parser will
 * be needed.  In principle, it might make sense to support python syntax, for
 * compatibility with the data engine, but compatibility in corner cases will be
 * fiddly given underlying differences between sqlite and python.
 */
export function parseFormula(txt: string): Formula {
  // Formula of form: $x.y
  let m = txt.match(/^\$([a-z]\w*)\.([a-z]\w*)$/i);
  if (m) {
    return {kind: 'foreignColumn', refColId: m[1], colId: m[2]};
  }

  // Formula of form: $x
  m = txt.match(/^\$([a-z][a-z_0-9]*)$/i);
  if (m) {
    return {kind: 'column', colId: m[1]};
  }

  // Formula of form: NNN
  m = txt.match(/^[0-9]+$/);
  if (m) {
    const value = parseInt(txt, 10);
    if (isNaN(value)) { return {kind: 'error', msg: 'Cannot parse integer'}; }
    return {kind: 'literalNumber', value};
  }

  // Everything else is an error.
  return {kind: 'error', msg: 'Formula not supported'};
}