<commit_before>/**
 * Copyright 2014 Mozilla Foundation
 *
 * 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.
 */
module Shumway.Remoting.Player {
  import MessageTag = Shumway.Remoting.MessageTag;
  import MessageBits = Shumway.Remoting.MessageBits;

  import flash = Shumway.AVMX.AS.flash;
  import Stage = flash.display.Stage;
  import Graphics = flash.display.Graphics;
  import NetStream = flash.net.NetStream;
  import display = flash.display;
  import Bitmap = flash.display.Bitmap;
  import BitmapData = flash.display.BitmapData;
  import DisplayObject = flash.display.DisplayObject;
  import DisplayObjectFlags = flash.display.DisplayObjectFlags;
  import DisplayObjectContainer = flash.display.DisplayObjectContainer;
  import BlendMode = flash.display.BlendMode;
  import PixelSnapping = flash.display.PixelSnapping;
  import VisitorFlags = flash.display.VisitorFlags;
  import Video = flash.media.Video;

  import Point = flash.geom.Point;
  import Bounds = Shumway.Bounds;
  import KeyboardEventData = flash.ui.KeyboardEventData;
  import MouseEventAndPointData = flash.ui.MouseEventAndPointData;
  import MouseCursor = flash.ui.MouseCursor;

  import IDataInput = Shumway.ArrayUtilities.IDataInput;
  import IDataOutput = Shumway.ArrayUtilities.IDataOutput;
  import DataBuffer = Shumway.ArrayUtilities.DataBuffer;
  import assert = Shumway.Debug.assert;
  import writer = Shumway.Player.writer;

  export class PlayerChannelSerializer {
    /**
     * Output buffer that the serializer writes to.
     */
    public output: DataBuffer;
    public outputAssets: any [];
    public phase: RemotingPhase = RemotingPhase.Objects;
    public roots: DisplayObject [] = null;

    constructor() {
      this.output = new DataBuffer();
      this.outputAssets = [];
    }

    remoteObjects() {
      this.phase = Remoting.RemotingPhase.Objects;
      var roots = this.roots;
      for (var i = 0; i < roots.length; i++) {
        Shumway.Player.enterTimeline("remoting objects");
        this.writeDirtyDisplayObjects(roots[i], false);
        Shumway.Player.leaveTimeline("remoting objects");
      }
    }

    remoteReferences() {
      this.phase = Remoting.RemotingPhase.References;
      var roots = this.roots;
      for (var i = 0; i < roots.length; i++) {
        Shumway.Player.enterTimeline("remoting references");
        this.writeDirtyDisplayObjects(roots[i], true);
        Shumway.Player.leaveTimeline("remoting references");
      }
    }

    writeEOF() {
      this.output.writeInt(Remoting.MessageTag.EOF);
    }

    /**
     * Serializes dirty display objects starting at the specified root |displayObject| node.
     */
    writeDirtyDisplayObjects(displayObject: DisplayObject, clearDirtyDescendentsFlag: boolean) {
      var self = this;
      var roots = this.roots;
      displayObject.visit(function (displayObject) {
        if (displayObject._hasAnyFlags(DisplayObjectFlags.Dirty)) {
          self.writeUpdateFrame(displayObject);
          // Collect more roots?
          if (roots && displayObject.mask) {
            var root = displayObject.mask._findFurthestAncestorOrSelf();
            Shumway.ArrayUtilities.pushUnique(roots, root)
          }
        }
        // TODO: Checking if we need to write assets this way is kinda expensive, do better here.
        self.writeDirtyAssets(displayObject);
        if (displayObject._hasFlags(DisplayObjectFlags.DirtyDescendents)) {
          return VisitorFlags.Continue;
        }
        if (clearDirtyDescendentsFlag) {
          // We need this flag to make sure we don't clear the flag in the first remoting pass.
          displayObject._removeFlags(DisplayObjectFlags.DirtyDescendents);
        }
        // We can skip visiting descendents since they are not dirty.
        return VisitorFlags.Skip;
      }, VisitorFlags.None);
    }

    writeStage(stage: Stage) {
      if (!stage._isDirty) {
        return;
      }
      writer && writer.writeLn("Sending Stage");
      var serializer = this;
      this.output.writeInt(MessageTag.UpdateStage);
      this.output.writeInt(stage._id);
      this.output.writeInt(stage.color);
      this._writeRectangle(new Bounds(0, 0, stage.stageWidth * 20, stage.stageHeight * 20));
      this.output.writeInt(flash.display.StageAlign.toNumber(stage.align));
      this.output.writeInt(flash.display.StageScaleMode.toNumber(stage.scaleMode));
      this.output.writeInt(flash.display.StageDisplayState.toNumber(stage.displayState));
      stage._isDirty = false;
    }

    writeCurrentMouseTarget(stage: Stage, currentMouseTarget: flash.display.InteractiveObject) {
      this.output.writeInt(MessageTag.UpdateCurrentMouseTarget);

      var sec = stage.sec;
      var Mouse = sec.flash.ui.Mouse.axClass;
      var cursor = Mouse.cursor;
      if (currentMouseTarget) {
        var SimpleButton = sec.flash.display.SimpleButton.axClass;
        var Sprite = sec.flash.display.Sprite.axClass;
        this.output.writeInt(currentMouseTarget._id);
        if (cursor === MouseCursor.AUTO) {
          var node = currentMouseTarget;
          do {
            if (SimpleButton.axIsType(node) ||
                (Sprite.axIsType(node) && (<flash.display.Sprite>node).buttonMode) &&
                (<any>currentMouseTarget).useHandCursor)
            {
              cursor = MouseCursor.BUTTON;
              break;
            }
            node = node._parent;
          } while (node && node !== stage);
        }
      } else {
        this.output.writeInt(-1);
      }
      this.output.writeInt(MouseCursor.toNumber(cursor));
    }

    writeGraphics(graphics: Graphics) {
      if (!graphics._isDirty) {
        return;
      }
      Shumway.Player.debugWriter && Shumway.Player.debugWriter.writeLn("Sending Graphics: " + graphics._id);
      var textures = graphics.getUsedTextures();
      var numTextures = textures.length;
      for (var i = 0; i < numTextures; i++) {
        textures[i] && this.writeBitmapData(textures[i]);
      }
      this.output.writeInt(MessageTag.UpdateGraphics);
      this.output.writeInt(graphics._id);
      this.output.writeInt(-1);
      this._writeRectangle(graphics._getContentBounds());
      this._writeAsset(graphics.getGraphicsData().toPlainObject());
      this.output.writeInt(numTextures);
      for (var i = 0; i < numTextures; i++) {
        this.output.writeInt(textures[i] ? textures[i]._id : -1);
      }
      graphics._isDirty = false;
    }

    writeNetStream(netStream: NetStream, bounds: Bounds) {
      if (!netStream._isDirty) {
        return;
      }<commit_msg>Remove leftover debug statement.<commit_after>/**
 * Copyright 2014 Mozilla Foundation
 *
 * 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.
 */
module Shumway.Remoting.Player {
  import MessageTag = Shumway.Remoting.MessageTag;
  import MessageBits = Shumway.Remoting.MessageBits;

  import flash = Shumway.AVMX.AS.flash;
  import Stage = flash.display.Stage;
  import Graphics = flash.display.Graphics;
  import NetStream = flash.net.NetStream;
  import display = flash.display;
  import Bitmap = flash.display.Bitmap;
  import BitmapData = flash.display.BitmapData;
  import DisplayObject = flash.display.DisplayObject;
  import DisplayObjectFlags = flash.display.DisplayObjectFlags;
  import DisplayObjectContainer = flash.display.DisplayObjectContainer;
  import BlendMode = flash.display.BlendMode;
  import PixelSnapping = flash.display.PixelSnapping;
  import VisitorFlags = flash.display.VisitorFlags;
  import Video = flash.media.Video;

  import Point = flash.geom.Point;
  import Bounds = Shumway.Bounds;
  import KeyboardEventData = flash.ui.KeyboardEventData;
  import MouseEventAndPointData = flash.ui.MouseEventAndPointData;
  import MouseCursor = flash.ui.MouseCursor;

  import IDataInput = Shumway.ArrayUtilities.IDataInput;
  import IDataOutput = Shumway.ArrayUtilities.IDataOutput;
  import DataBuffer = Shumway.ArrayUtilities.DataBuffer;
  import assert = Shumway.Debug.assert;
  import writer = Shumway.Player.writer;

  export class PlayerChannelSerializer {
    /**
     * Output buffer that the serializer writes to.
     */
    public output: DataBuffer;
    public outputAssets: any [];
    public phase: RemotingPhase = RemotingPhase.Objects;
    public roots: DisplayObject [] = null;

    constructor() {
      this.output = new DataBuffer();
      this.outputAssets = [];
    }

    remoteObjects() {
      this.phase = Remoting.RemotingPhase.Objects;
      var roots = this.roots;
      for (var i = 0; i < roots.length; i++) {
        Shumway.Player.enterTimeline("remoting objects");
        this.writeDirtyDisplayObjects(roots[i], false);
        Shumway.Player.leaveTimeline("remoting objects");
      }
    }

    remoteReferences() {
      this.phase = Remoting.RemotingPhase.References;
      var roots = this.roots;
      for (var i = 0; i < roots.length; i++) {
        Shumway.Player.enterTimeline("remoting references");
        this.writeDirtyDisplayObjects(roots[i], true);
        Shumway.Player.leaveTimeline("remoting references");
      }
    }

    writeEOF() {
      this.output.writeInt(Remoting.MessageTag.EOF);
    }

    /**
     * Serializes dirty display objects starting at the specified root |displayObject| node.
     */
    writeDirtyDisplayObjects(displayObject: DisplayObject, clearDirtyDescendentsFlag: boolean) {
      var self = this;
      var roots = this.roots;
      displayObject.visit(function (displayObject) {
        if (displayObject._hasAnyFlags(DisplayObjectFlags.Dirty)) {
          self.writeUpdateFrame(displayObject);
          // Collect more roots?
          if (roots && displayObject.mask) {
            var root = displayObject.mask._findFurthestAncestorOrSelf();
            Shumway.ArrayUtilities.pushUnique(roots, root)
          }
        }
        // TODO: Checking if we need to write assets this way is kinda expensive, do better here.
        self.writeDirtyAssets(displayObject);
        if (displayObject._hasFlags(DisplayObjectFlags.DirtyDescendents)) {
          return VisitorFlags.Continue;
        }
        if (clearDirtyDescendentsFlag) {
          // We need this flag to make sure we don't clear the flag in the first remoting pass.
          displayObject._removeFlags(DisplayObjectFlags.DirtyDescendents);
        }
        // We can skip visiting descendents since they are not dirty.
        return VisitorFlags.Skip;
      }, VisitorFlags.None);
    }

    writeStage(stage: Stage) {
      if (!stage._isDirty) {
        return;
      }
      writer && writer.writeLn("Sending Stage");
      var serializer = this;
      this.output.writeInt(MessageTag.UpdateStage);
      this.output.writeInt(stage._id);
      this.output.writeInt(stage.color);
      this._writeRectangle(new Bounds(0, 0, stage.stageWidth * 20, stage.stageHeight * 20));
      this.output.writeInt(flash.display.StageAlign.toNumber(stage.align));
      this.output.writeInt(flash.display.StageScaleMode.toNumber(stage.scaleMode));
      this.output.writeInt(flash.display.StageDisplayState.toNumber(stage.displayState));
      stage._isDirty = false;
    }

    writeCurrentMouseTarget(stage: Stage, currentMouseTarget: flash.display.InteractiveObject) {
      this.output.writeInt(MessageTag.UpdateCurrentMouseTarget);

      var sec = stage.sec;
      var Mouse = sec.flash.ui.Mouse.axClass;
      var cursor = Mouse.cursor;
      if (currentMouseTarget) {
        var SimpleButton = sec.flash.display.SimpleButton.axClass;
        var Sprite = sec.flash.display.Sprite.axClass;
        this.output.writeInt(currentMouseTarget._id);
        if (cursor === MouseCursor.AUTO) {
          var node = currentMouseTarget;
          do {
            if (SimpleButton.axIsType(node) ||
                (Sprite.axIsType(node) && (<flash.display.Sprite>node).buttonMode) &&
                (<any>currentMouseTarget).useHandCursor)
            {
              cursor = MouseCursor.BUTTON;
              break;
            }
            node = node._parent;
          } while (node && node !== stage);
        }
      } else {
        this.output.writeInt(-1);
      }
      this.output.writeInt(MouseCursor.toNumber(cursor));
    }

    writeGraphics(graphics: Graphics) {
      if (!graphics._isDirty) {
        return;
      }
      var textures = graphics.getUsedTextures();
      var numTextures = textures.length;
      for (var i = 0; i < numTextures; i++) {
        textures[i] && this.writeBitmapData(textures[i]);
      }
      this.output.writeInt(MessageTag.UpdateGraphics);
      this.output.writeInt(graphics._id);
      this.output.writeInt(-1);
      this._writeRectangle(graphics._getContentBounds());
      this._writeAsset(graphics.getGraphicsData().toPlainObject());
      this.output.writeInt(numTextures);
      for (var i = 0; i < numTextures; i++) {
        this.output.writeInt(textures[i] ? textures[i]._id : -1);
      }
      graphics._isDirty = false;
    }

    writeNetStream(netStream: NetStream, bounds: Bounds) {
      if (!netStream._isDirty) {
        return;
      }
{'fraction_non_alphanumeric': 0.10341880341880341, 'fraction_numerical': 0.0029914529914529917, 'mean_word_length': 2.9396745230078563, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5297573', 'n_tokens_mistral': 4050, 'n_tokens_neox': 3959, 'n_words': 889}