// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

part of app;

class Notification {
  Notification.fromEvent(this.event);
  Notification.fromException(this.exception, this.stacktrace);

  ServiceEvent event;
  var exception;
  var stacktrace;
}

/// The observatory application. Instances of this are created and owned
/// by the observatory_application custom element.
class ObservatoryApplication extends Observable {
  static ObservatoryApplication app;
  final _pageRegistry = new List<Page>();
  LocationManager _locationManager;
  LocationManager get locationManager => _locationManager;
  @observable Page currentPage;
  VM _vm;
  VM get vm => _vm;

  set vm(VM vm) {
    if (_vm == vm) {
      // Do nothing.
      return;
    }
    if (_vm != null) {
      // Disconnect from current VM.
      notifications.clear();
      _vm.disconnect();
    }
    if (vm != null) {
      Logger.root.info('Registering new VM callbacks');

      vm.onConnect.then((_) {
        if (vm is WebSocketVM) {
          targets.add(vm.target);
        }
        _removeDisconnectEvents();
      });

      vm.onDisconnect.then((String reason) {
        if (this.vm != vm) {
          // This disconnect event occured *after* a new VM was installed.
          return;
        }
        notifications.add(
            new Notification.fromEvent(
                new ServiceEvent.connectionClosed(reason)));
      });

      vm.listenEventStream(VM.kIsolateStream, _onEvent);
      vm.listenEventStream(VM.kDebugStream, _onEvent);
    }
    _vm = vm;
  }
  final TargetManager targets;
  @reflectable final ObservatoryApplicationElement rootElement;

  TraceViewElement _traceView = null;

  @reflectable ServiceObject lastErrorOrException;
  @observable ObservableList<Notification> notifications =
      new ObservableList<Notification>();

  void _initOnce() {
    assert(app == null);
    app = this;
    _registerPages();
    Analytics.initialize();
    // Visit the current page.
    locationManager._visit();
  }

  void removePauseEvents(Isolate isolate) {
    notifications.removeWhere((notification) {
        var event = notification.event;
        return (event != null &&
                event.isolate == isolate &&
                event.isPauseEvent);
      });
  }

  void _onEvent(ServiceEvent event) {
    switch(event.kind) {
      case ServiceEvent.kIsolateStart:
      case ServiceEvent.kIsolateRunnable:
      case ServiceEvent.kIsolateUpdate:
      case ServiceEvent.kBreakpointAdded:
      case ServiceEvent.kBreakpointResolved:
      case ServiceEvent.kBreakpointRemoved:
      case ServiceEvent.kDebuggerSettingsUpdate:
        // Ignore for now.
        break;

      case ServiceEvent.kIsolateExit:
      case ServiceEvent.kResume:
        removePauseEvents(event.isolate);
        break;

      case ServiceEvent.kPauseStart:
      case ServiceEvent.kPauseExit:
      case ServiceEvent.kPauseBreakpoint:
      case ServiceEvent.kPauseInterrupted:
      case ServiceEvent.kPauseException:
        removePauseEvents(event.isolate);
        notifications.add(new Notification.fromEvent(event));
        break;

      case ServiceEvent.kInspect:
        notifications.add(new Notification.fromEvent(event));
        break;

      default:
        // Ignore unrecognized events.
        Logger.root.severe('Unrecognized event: $event');
        break;
    }
  }

  void _registerPages() {
    _pageRegistry.add(new VMPage(this));
    _pageRegistry.add(new FlagsPage(this));
    _pageRegistry.add(new InspectPage(this));
    _pageRegistry.add(new ClassTreePage(this));
    _pageRegistry.add(new DebuggerPage(this));
    _pageRegistry.add(new CpuProfilerPage(this));
    _pageRegistry.add(new TableCpuProfilerPage(this));
    _pageRegistry.add(new AllocationProfilerPage(this));
    _pageRegistry.add(new HeapMapPage(this));
    _pageRegistry.add(new HeapSnapshotPage(this));
    _pageRegistry.add(new VMConnectPage(this));
    _pageRegistry.add(new IsolateReconnectPage(this));
    _pageRegistry.add(new ErrorViewPage(this));
    _pageRegistry.add(new MetricsPage(this));
    _pageRegistry.add(new PortsPage(this));
    _pageRegistry.add(new LoggingPage(this));
    // Note that ErrorPage must be the last entry in the list as it is
    // the catch all.
    _pageRegistry.add(new ErrorPage(this));
  }

  void _visit(Uri uri, Map internalArguments) {
    if (internalArguments['trace'] != null) {
      var traceArg = internalArguments['trace'];
      if (traceArg == 'on') {
        Tracer.start();
      } else if (traceArg == 'off') {
        Tracer.stop();
      }
    }
    if (Tracer.current != null) {
      Tracer.current.reset();
    }
    if (_traceView != null) {
      _traceView.tracer = Tracer.current;
    }
    for (var i = 0; i < _pageRegistry.length; i++) {
      var page = _pageRegistry[i];
      if (page.canVisit(uri)) {
        _installPage(page);
        page.visit(uri, internalArguments);
        return;
      }
    }
    throw new FallThroughError();
  }

  /// Set the Observatory application page.
  void _installPage(Page page) {
    assert(page != null);
    if (currentPage == page) {
      // Already isntalled.
      return;
    }
    if (currentPage != null) {
      Logger.root.info('Uninstalling page: $currentPage');
      currentPage.onUninstall();
      // Clear children.
      rootElement.children.clear();
    }
    Logger.root.info('Installing page: $page');
    try {
      page.onInstall();
    } catch (e) {
      Logger.root.severe('Failed to install page: $e');
    }
    // Add new page.
    rootElement.children.add(page.element);

    // Add tracing support.
    _traceView = new Element.tag('trace-view');
    _traceView.tracer = Tracer.current;
    rootElement.children.add(_traceView);

    // Remember page.
    currentPage = page;
  }

  ObservatoryApplication(this.rootElement) :
      targets = new TargetManager() {
    _locationManager = new LocationManager(this);
    vm = new WebSocketVM(targets.defaultTarget);
    _initOnce();
  }

  void _removeDisconnectEvents() {
    notifications.removeWhere((notification) {
        var event = notification.event;
        return (event != null &&
                event.kind == ServiceEvent.kConnectionClosed);
      });
  }

  loadCrashDump(Map crashDump) {
    this.vm = new FakeVM(crashDump['result']);
    app.locationManager.go('#/vm');
  }

  void handleException(e, st) {
    // TODO(turnidge): Report this failure via analytics.
    Logger.root.warning('Caught exception: ${e}\n${st}');
    notifications.add(new Notification.fromException(e, st));
  }

  // This map keeps track of which curly-blocks have been expanded by the user.
  Map<String,bool> expansions = {};
}
