// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use size 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.

import m from 'mithril';

import {currentTargetOffset} from '../base/dom_utils';
import {Icons} from '../base/semantic_icons';
import {Time} from '../base/time';
import {Actions} from '../common/actions';
import {randomColor} from '../common/colorizer';
import {AreaNote, Note} from '../common/state';
import {raf} from '../core/raf_scheduler';
import {Button} from '../widgets/button';

import {
  BottomTab,
  bottomTabRegistry,
  NewBottomTabArgs,
} from './bottom_tab';
import {TRACK_SHELL_WIDTH} from './css_constants';
import {globals} from './globals';
import {
  getMaxMajorTicks,
  TickGenerator,
  TickType,
  timeScaleForVisibleWindow,
} from './gridline_helper';
import {PanelSize} from './panel';
import {Panel} from './panel_container';
import {isTraceLoaded} from './sidebar';
import {Timestamp} from './widgets/timestamp';

const FLAG_WIDTH = 16;
const AREA_TRIANGLE_WIDTH = 10;
const FLAG = `\uE153`;

function toSummary(s: string) {
  const newlineIndex = s.indexOf('\n') > 0 ? s.indexOf('\n') : s.length;
  return s.slice(0, Math.min(newlineIndex, s.length, 16));
}

function getStartTimestamp(note: Note|AreaNote) {
  if (note.noteType === 'AREA') {
    return globals.state.areas[note.areaId].start;
  } else {
    return note.timestamp;
  }
}

export class NotesPanel implements Panel {
  readonly kind = 'panel';
  readonly selectable = false;
  readonly trackKey = undefined;

  hoveredX: null|number = null;

  constructor(readonly key: string) {}

  get mithril(): m.Children {
    const allCollapsed = Object.values(globals.state.trackGroups)
      .every((group) => group.collapsed);

    return m(
      '.notes-panel',
      {
        onclick: (e: MouseEvent) => {
          const {x, y} = currentTargetOffset(e);
          this.onClick(x - TRACK_SHELL_WIDTH, y);
          e.stopPropagation();
        },
        onmousemove: (e: MouseEvent) => {
          this.hoveredX = currentTargetOffset(e).x - TRACK_SHELL_WIDTH;
          raf.scheduleRedraw();
        },
        mouseenter: (e: MouseEvent) => {
          this.hoveredX = currentTargetOffset(e).x - TRACK_SHELL_WIDTH;
          raf.scheduleRedraw();
        },
        onmouseout: () => {
          this.hoveredX = null;
          globals.dispatch(
            Actions.setHoveredNoteTimestamp({ts: Time.INVALID}));
        },
      },
      isTraceLoaded() ?
        [
          m('button',
            {
              onclick: (e: Event) => {
                e.preventDefault();
                globals.dispatch(Actions.toggleAllTrackGroups(
                  {collapsed: !allCollapsed}));
              },
            },
            m('i.material-icons',
              {title: allCollapsed ? 'Expand all' : 'Collapse all'},
              allCollapsed ? 'unfold_more' : 'unfold_less')),
          m('button',
            {
              onclick: (e: Event) => {
                e.preventDefault();
                globals.dispatch(Actions.clearAllPinnedTracks({}));
              },
            },
            m('i.material-icons',
              {title: 'Clear all pinned tracks'},
              'clear_all')),
        ] :
        '');
  }

  renderCanvas(ctx: CanvasRenderingContext2D, size: PanelSize) {
    let aNoteIsHovered = false;

    ctx.fillStyle = '#999';
    ctx.fillRect(TRACK_SHELL_WIDTH - 2, 0, 2, size.height);

    ctx.save();
    ctx.beginPath();
    ctx.rect(TRACK_SHELL_WIDTH, 0, size.width - TRACK_SHELL_WIDTH, size.height);
    ctx.clip();

    const span = globals.timeline.visibleTimeSpan;
    const {visibleTimeScale} = globals.timeline;
    if (size.width > TRACK_SHELL_WIDTH && span.duration > 0n) {
      const maxMajorTicks = getMaxMajorTicks(size.width - TRACK_SHELL_WIDTH);
      const map = timeScaleForVisibleWindow(TRACK_SHELL_WIDTH, size.width);
      const offset = globals.timestampOffset();
      const tickGen = new TickGenerator(span, maxMajorTicks, offset);
      for (const {type, time} of tickGen) {
        const px = Math.floor(map.timeToPx(time));
        if (type === TickType.MAJOR) {
          ctx.fillRect(px, 0, 1, size.height);
        }
      }
    }

    ctx.textBaseline = 'bottom';
    ctx.font = '10px Helvetica';

    for (const note of Object.values(globals.state.notes)) {
      const timestamp = getStartTimestamp(note);
      // TODO(hjd): We should still render area selection marks in viewport is
      // *within* the area (e.g. both lhs and rhs are out of bounds).
      if ((note.noteType !== 'AREA' && !span.contains(timestamp)) ||
          (note.noteType === 'AREA' &&
           !span.contains(globals.state.areas[note.areaId].end) &&
           !span.contains(globals.state.areas[note.areaId].start))) {
        continue;
      }
      const currentIsHovered =
          this.hoveredX !== null && this.mouseOverNote(this.hoveredX, note);
      if (currentIsHovered) aNoteIsHovered = true;

      const selection = globals.state.currentSelection;
      const isSelected = selection !== null &&
          ((selection.kind === 'NOTE' && selection.id === note.id) ||
           (selection.kind === 'AREA' && selection.noteId === note.id));
      const x = visibleTimeScale.timeToPx(timestamp);
      const left = Math.floor(x + TRACK_SHELL_WIDTH);

      // Draw flag or marker.
      if (note.noteType === 'AREA') {
        const area = globals.state.areas[note.areaId];
        this.drawAreaMarker(
          ctx,
          left,
          Math.floor(visibleTimeScale.timeToPx(area.end) + TRACK_SHELL_WIDTH),
          note.color,
          isSelected);
      } else {
        this.drawFlag(ctx, left, size.height, note.color, isSelected);
      }

      if (note.text) {
        const summary = toSummary(note.text);
        const measured = ctx.measureText(summary);
        // Add a white semi-transparent background for the text.
        ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
        ctx.fillRect(
          left + FLAG_WIDTH + 2, size.height + 2, measured.width + 2, -12);
        ctx.fillStyle = '#3c4b5d';
        ctx.fillText(summary, left + FLAG_WIDTH + 3, size.height + 1);
      }
    }

    // A real note is hovered so we don't need to see the preview line.
    // TODO(hjd): Change cursor to pointer here.
    if (aNoteIsHovered) {
      globals.dispatch(Actions.setHoveredNoteTimestamp({ts: Time.INVALID}));
    }

    // View preview note flag when hovering on notes panel.
    if (!aNoteIsHovered && this.hoveredX !== null) {
      const timestamp = visibleTimeScale.pxToHpTime(this.hoveredX).toTime();
      if (span.contains(timestamp)) {
        globals.dispatch(Actions.setHoveredNoteTimestamp({ts: timestamp}));
        const x = visibleTimeScale.timeToPx(timestamp);
        const left = Math.floor(x + TRACK_SHELL_WIDTH);
        this.drawFlag(ctx, left, size.height, '#aaa', /* fill */ true);
      }
    }

    ctx.restore();
  }

  private drawAreaMarker(
    ctx: CanvasRenderingContext2D, x: number, xEnd: number, color: string,
    fill: boolean) {
    ctx.fillStyle = color;
    ctx.strokeStyle = color;
    const topOffset = 10;
    // Don't draw in the track shell section.
    if (x >= TRACK_SHELL_WIDTH) {
      // Draw left triangle.
      ctx.beginPath();
      ctx.moveTo(x, topOffset);
      ctx.lineTo(x, topOffset + AREA_TRIANGLE_WIDTH);
      ctx.lineTo(x + AREA_TRIANGLE_WIDTH, topOffset);
      ctx.lineTo(x, topOffset);
      if (fill) ctx.fill();
      ctx.stroke();
    }
    // Draw right triangle.
    ctx.beginPath();
    ctx.moveTo(xEnd, topOffset);
    ctx.lineTo(xEnd, topOffset + AREA_TRIANGLE_WIDTH);
    ctx.lineTo(xEnd - AREA_TRIANGLE_WIDTH, topOffset);
    ctx.lineTo(xEnd, topOffset);
    if (fill) ctx.fill();
    ctx.stroke();

    // Start line after track shell section, join triangles.
    const startDraw = Math.max(x, TRACK_SHELL_WIDTH);
    ctx.beginPath();
    ctx.moveTo(startDraw, topOffset);
    ctx.lineTo(xEnd, topOffset);
    ctx.stroke();
  }

  private drawFlag(
    ctx: CanvasRenderingContext2D, x: number, height: number, color: string,
    fill?: boolean) {
    const prevFont = ctx.font;
    const prevBaseline = ctx.textBaseline;
    ctx.textBaseline = 'alphabetic';
    // Adjust height for icon font.
    ctx.font = '24px Material Symbols Sharp';
    ctx.fillStyle = color;
    ctx.strokeStyle = color;
    // The ligatures have padding included that means the icon is not drawn
    // exactly at the x value. This adjusts for that.
    const iconPadding = 6;
    if (fill) {
      ctx.fillText(FLAG, x - iconPadding, height + 2);
    } else {
      ctx.strokeText(FLAG, x - iconPadding, height + 2.5);
    }
    ctx.font = prevFont;
    ctx.textBaseline = prevBaseline;
  }


  private onClick(x: number, _: number) {
    if (x < 0) return;
    const {visibleTimeScale} = globals.timeline;
    const timestamp = visibleTimeScale.pxToHpTime(x).toTime();
    for (const note of Object.values(globals.state.notes)) {
      if (this.hoveredX !== null && this.mouseOverNote(this.hoveredX, note)) {
        if (note.noteType === 'AREA') {
          globals.makeSelection(
            Actions.reSelectArea({areaId: note.areaId, noteId: note.id}));
        } else {
          globals.makeSelection(Actions.selectNote({id: note.id}));
        }
        return;
      }
    }
    const color = randomColor();
    globals.makeSelection(Actions.addNote({timestamp, color}));
  }

  private mouseOverNote(x: number, note: AreaNote|Note): boolean {
    const timeScale = globals.timeline.visibleTimeScale;
    const noteX = timeScale.timeToPx(getStartTimestamp(note));
    if (note.noteType === 'AREA') {
      const noteArea = globals.state.areas[note.areaId];
      return (noteX <= x && x < noteX + AREA_TRIANGLE_WIDTH) ||
          (timeScale.timeToPx(noteArea.end) > x &&
           x > timeScale.timeToPx(noteArea.end) - AREA_TRIANGLE_WIDTH);
    } else {
      const width = FLAG_WIDTH;
      return noteX <= x && x < noteX + width;
    }
  }
}

interface NotesEditorTabConfig {
  id: string;
}

export class NotesEditorTab extends BottomTab<NotesEditorTabConfig> {
  static readonly kind = 'org.perfetto.NotesEditorTab';

  static create(args: NewBottomTabArgs<NotesEditorTabConfig>): NotesEditorTab {
    return new NotesEditorTab(args);
  }

  constructor(args: NewBottomTabArgs<NotesEditorTabConfig>) {
    super(args);
  }

  getTitle() {
    return 'Current Selection';
  }

  viewTab() {
    const note = globals.state.notes[this.config.id];
    if (note === undefined) {
      return m('.', `No Note with id ${this.config.id}`);
    }
    const startTime = getStartTimestamp(note);
    return m(
      '.notes-editor-panel',
      m('.notes-editor-panel-heading-bar',
        m('.notes-editor-panel-heading',
          `Annotation at `,
          m(Timestamp, {ts: startTime})),
        m('input[type=text]', {
          value: note.text,
          onchange: (e: InputEvent) => {
            const newText = (e.target as HTMLInputElement).value;
            globals.dispatch(Actions.changeNoteText({
              id: this.config.id,
              newText,
            }));
          },
        }),
        m('span.color-change', `Change color: `, m('input[type=color]', {
          value: note.color,
          onchange: (e: Event) => {
            const newColor = (e.target as HTMLInputElement).value;
            globals.dispatch(Actions.changeNoteColor({
              id: this.config.id,
              newColor,
            }));
          },
        })),
        m(Button, {
          label: 'Remove',
          icon: Icons.Delete,
          minimal: true,
          onclick: () => {
            globals.dispatch(Actions.removeNote({id: this.config.id}));
            globals.dispatch(Actions.setCurrentTab({tab: undefined}));
            raf.scheduleFullRedraw();
          },
        })),
    );
  }
}

bottomTabRegistry.register(NotesEditorTab);
