// Copyright (C) 2020 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 * as m from 'mithril';

import {Actions} from '../common/actions';

import {Flow, globals} from './globals';
import {BLANK_CHECKBOX, CHECKBOX} from './icons';
import {Panel, PanelSize} from './panel';

export const ALL_CATEGORIES = '_all_';

export function getFlowCategories(flow: Flow): string[] {
  const categories: string[] = [];
  // v1 flows have their own categories
  if (flow.category) {
    categories.push(...flow.category.split(','));
    return categories;
  }
  const beginCats = flow.begin.sliceCategory.split(',');
  const endCats = flow.end.sliceCategory.split(',');
  categories.push(...new Set([...beginCats, ...endCats]));
  return categories;
}

export class FlowEventsPanel extends Panel {
  view() {
    const selection = globals.state.currentSelection;
    if (!selection || selection.kind !== 'CHROME_SLICE') {
      return;
    }

    const flowClickHandler = (sliceId: number, trackId: number) => {
      const uiTrackId = globals.state.uiTrackIdByTraceTrackId[trackId];
      if (uiTrackId) {
        globals.makeSelection(
            Actions.selectChromeSlice(
                {id: sliceId, trackId: uiTrackId, table: 'slice'}),
            'bound_flows');
      }
    };

    // Can happen only for flow events version 1
    const haveCategories =
        globals.connectedFlows.filter(flow => flow.category).length > 0;

    const columns = [
      m('th', 'Direction'),
      m('th', 'Connected Slice ID'),
      m('th', 'Connected Slice Name')
    ];

    if (haveCategories) {
      columns.push(m('th', 'Flow Category'));
      columns.push(m('th', 'Flow Name'));
    }

    const rows = [m('tr', columns)];

    // Fill the table with all the directly connected flow events
    globals.connectedFlows.forEach(flow => {
      if (selection.id !== flow.begin.sliceId &&
          selection.id !== flow.end.sliceId) {
        return;
      }

      const outgoing = selection.id === flow.begin.sliceId;
      const otherEnd = (outgoing ? flow.end : flow.begin);

      const args = {
        onclick: () => flowClickHandler(otherEnd.sliceId, otherEnd.trackId),
        onmousemove: () => globals.dispatch(
            Actions.setHighlightedSliceId({sliceId: otherEnd.sliceId})),
        onmouseleave: () =>
            globals.dispatch(Actions.setHighlightedSliceId({sliceId: -1})),
      };

      const data = [
        m('td.flow-link', args, outgoing ? 'Outgoing' : 'Incoming'),
        m('td.flow-link', args, otherEnd.sliceId.toString()),
        m('td.flow-link', args, otherEnd.sliceName)
      ];

      if (haveCategories) {
        data.push(m('td.flow-info', flow.category || '-'));
        data.push(m('td.flow-info', flow.name || '-'));
      }

      rows.push(m('tr', data));
    });

    return m('.details-panel', [
      m('.details-panel-heading', m('h2', `Flow events`)),
      m('.flow-events-table', m('table.half-width', rows))
    ]);
  }

  renderCanvas(_ctx: CanvasRenderingContext2D, _size: PanelSize) {}
}

export class FlowEventsAreaSelectedPanel extends Panel {
  view() {
    const selection = globals.state.currentSelection;
    if (!selection || selection.kind !== 'AREA') {
      return;
    }

    const columns = [
      m('th', 'Flow Category'),
      m('th', 'Number of flows'),
      m('th',
        'Show',
        m('a.warning',
          m('i.material-icons', 'warning'),
          m('.tooltip',
            'Showing a large number of flows may impact performance.')))
    ];

    const rows = [m('tr', columns)];

    const categoryToFlowsNum = new Map<string, number>();

    globals.selectedFlows.forEach(flow => {
      const categories = getFlowCategories(flow);
      categories.forEach(cat => {
        if (!categoryToFlowsNum.has(cat)) {
          categoryToFlowsNum.set(cat, 0);
        }
        categoryToFlowsNum.set(cat, categoryToFlowsNum.get(cat)! + 1);
      });
    });

    const allWasChecked = globals.visibleFlowCategories.get(ALL_CATEGORIES);
    rows.push(m('tr.sum', [
      m('td.sum-data', 'All'),
      m('td.sum-data', globals.selectedFlows.length),
      m('td.sum-data',
        m('i.material-icons',
          {
            onclick: () => {
              if (allWasChecked) {
                globals.visibleFlowCategories.clear();
              } else {
                categoryToFlowsNum.forEach((_, cat) => {
                  globals.visibleFlowCategories.set(cat, true);
                });
              }
              globals.visibleFlowCategories.set(ALL_CATEGORIES, !allWasChecked);
              globals.rafScheduler.scheduleFullRedraw();
            },
          },
          allWasChecked ? CHECKBOX : BLANK_CHECKBOX))
    ]));

    categoryToFlowsNum.forEach((num, cat) => {
      const wasChecked = globals.visibleFlowCategories.get(cat) ||
          globals.visibleFlowCategories.get(ALL_CATEGORIES);
      const data = [
        m('td.flow-info', cat),
        m('td.flow-info', num),
        m('td.flow-info',
          m('i.material-icons',
            {
              onclick: () => {
                if (wasChecked) {
                  globals.visibleFlowCategories.set(ALL_CATEGORIES, false);
                }
                globals.visibleFlowCategories.set(cat, !wasChecked);
                globals.rafScheduler.scheduleFullRedraw();
              },
            },
            wasChecked ? CHECKBOX : BLANK_CHECKBOX))
      ];
      rows.push(m('tr', data));
    });

    return m('.details-panel', [
      m('.details-panel-heading', m('h2', `Selected flow events`)),
      m('.flow-events-table', m('table.half-width', rows)),
    ]);
  }

  renderCanvas(_ctx: CanvasRenderingContext2D, _size: PanelSize) {}
}
