<commit_before>/*************************************************************************
 *                                                                       *
 * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith.       *
 * All rights reserved.  Email: russ@q12.org   Web: www.q12.org          *
 *                                                                       *
 * This library is free software; you can redistribute it and/or         *
 * modify it under the terms of EITHER:                                  *
 *   (1) The GNU Lesser General Public License as published by the Free  *
 *       Software Foundation; either version 2.1 of the License, or (at  *
 *       your option) any later version. The text of the GNU Lesser      *
 *       General Public License is included with this library in the     *
 *       file LICENSE.TXT.                                               *
 *   (2) The BSD-style license that is included with this library in     *
 *       the file LICENSE-BSD.TXT.                                       *
 *                                                                       *
 * This library is distributed in the hope that it will be useful,       *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files    *
 * LICENSE.TXT and LICENSE-BSD.TXT for more details.                     *
 *                                                                       *
 *************************************************************************/

// main window and event handling for X11

#include <ode/config.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include <GL/glx.h>

#include <drawstuff/drawstuff.h>
#include <drawstuff/version.h>
#include "internal.h"

//***************************************************************************
// error handling for unix

static void printMessage (char *msg1, char *msg2, va_list ap)
{
  fflush (stderr);
  fflush (stdout);
  fprintf (stderr,"\n%s: ",msg1);
  vfprintf (stderr,msg2,ap);
  fprintf (stderr,"\n");
  fflush (stderr);
}

extern "C" void dsError (char *msg, ...)
{
  va_list ap;
  va_start (ap,msg);
  printMessage ("Error",msg,ap);
  exit (1);
}

extern "C" void dsDebug (char *msg, ...)
{
  va_list ap;
  va_start (ap,msg);
  printMessage ("INTERNAL ERROR",msg,ap);
  // *((char *)0) = 0;	 ... commit SEGVicide ?
  abort();
}

extern "C" void dsPrint (char *msg, ...)
{
  va_list ap;
  va_start (ap,msg);
  vprintf (msg,ap);
}

//***************************************************************************
// openGL window

// X11 display info
static Display *display=0;
static int screen=0;
static XVisualInfo *visual=0;		// best visual for openGL
static Colormap colormap=0;		// window's colormap
static Atom wm_protocols_atom = 0;
static Atom wm_delete_window_atom = 0;

// window and openGL
static Window win=0;			// X11 window, 0 if not initialized
static int width=0,height=0;		// window size
static GLXContext glx_context=0;	// openGL rendering context
static int last_key_pressed=0;		// last key pressed in the window
static int run=1;			// 1 if simulation running
static int pause=0;			// 1 if in `pause' mode
static int singlestep=0;		// 1 if single step key pressed
static int writeframes=0;		// 1 if frame files to be written

static void createMainWindow (int _width, int _height)
{
  // create X11 display connection
  display = XOpenDisplay (0);
  if (!display) dsError (0,"can not open X11 display");
  screen = DefaultScreen(display);

  // get GL visual
  static int attribList[] = {GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE,16,
			     GLX_RED_SIZE,4, GLX_GREEN_SIZE,4,
			     GLX_BLUE_SIZE,4, None};
  visual = glXChooseVisual (display,screen,attribList);
  if (!visual) dsError ("no good X11 visual found for OpenGL");

  // create colormap
  colormap = XCreateColormap (display,RootWindow(display,screen),
			      visual->visual,AllocNone);

  // initialize variables
  win = 0;
  width = _width;
  height = _height;
  glx_context = 0;
  last_key_pressed = 0;

  if (width < 1 || height < 1) dsDebug (0,"bad window width or height");

  // create the window
  XSetWindowAttributes attributes;
  attributes.background_pixel = BlackPixel(display,screen);
  attributes.colormap = colormap;
  attributes.event_mask = ButtonPressMask | ButtonReleaseMask |
    KeyPressMask | KeyReleaseMask | ButtonMotionMask | PointerMotionHintMask |
    StructureNotifyMask;
  win = XCreateWindow (display,RootWindow(display,screen),50,50,width,height,
		       0,visual->depth, InputOutput,visual->visual,
		       CWBackPixel | CWColormap | CWEventMask,&attributes);

  // associate a GLX context with the window
  glx_context = glXCreateContext (display,visual,0,GL_TRUE);
  if (!glx_context) dsError ("can't make an OpenGL context");

  // set the window title
  XTextProperty window_name;
  window_name.value = (unsigned char *) "Simulation";
  window_name.encoding = XA_STRING;
  window_name.format = 8;
  window_name.nitems = strlen((char *) window_name.value);
  XSetWMName (display,win,&window_name);

  // participate in the window manager 'delete yourself' protocol
  wm_protocols_atom = XInternAtom (display,"WM_PROTOCOLS",False);
  wm_delete_window_atom = XInternAtom (display,"WM_DELETE_WINDOW",False);
  if (XSetWMProtocols (display,win,&wm_delete_window_atom,1)==0)
    dsError ("XSetWMProtocols() call failed");

  // pop up the window
  XMapWindow (display,win);
  XSync (display,win);
}

static void destroyMainWindow()
{
  glXDestroyContext (display,glx_context);
  XDestroyWindow (display,win);
  XSync (display,0);
  display = 0;
  win = 0;
  glx_context = 0;
}

static void handleEvent (XEvent &event, dsFunctions *fn)
{
  static int mx=0,my=0; 	// mouse position
  static int mode = 0;		// mouse button bits

  switch (event.type) {

  case ButtonPress: {
    if (event.xbutton.button == Button1) mode |= 1;
    if (event.xbutton.button == Button2) mode |= 2;
    if (event.xbutton.button == Button3) mode |= 4;
    mx = event.xbutton.x;
    my = event.xbutton.y;
  }
  return;

  case ButtonRelease: {
    if (event.xbutton.button == Button1) mode &= (~1);
    if (event.xbutton.button == Button2) mode &= (~2);
    if (event.xbutton.button == Button3) mode &= (~4);
    mx = event.xbutton.x;
    my = event.xbutton.x;
  }
  return;

  case MotionNotify: {
    if (event.xmotion.is_hint) {
      Window root,child;
      unsigned int mask;
      XQueryPointer (display,win,&root,&child,&event.xbutton.x_root,
		     &event.xbutton.y_root,&event.xbutton.x,&event.xbutton.y,
		     &mask);
    }
    dsMotion (mode, event.xmotion.x - mx, event.xmotion.y - my);
    mx = event.xmotion.x;
    my = event.xmotion.y;
  }
  return;

  case KeyPress: {
    KeySym key;
    XLookupString (&event.xkey,NULL,0,&key,0);
    if ((event.xkey.state & ControlMask) == 0) {
      if (key >= ' ' && key <= 126 && fn->command) fn->command (key);
    }
    else if (event.xkey.state & ControlMask) {
      switch (key) {
      case 't': case 'T':
	dsSetTextures (dsGetTextures() ^ 1);
	break;
      case 's': case 'S':
	dsSetShadows (dsGetShadows() ^ 1);
	break;
      case 'x': case 'X':
	run = 0;
	break;
      case 'p': case 'P':
	pause ^= 1;
	singlestep = 0;
	break;
      case 'o': case 'O':
	if (pause) singlestep = 1;
	break;
      case 'v': case 'V': {
	float xyz[3],hpr[3];
	dsGetViewpoint (xyz,hpr);
	printf ("Viewpoint = (%.4f,%.4f,%.4f,%.4f,%.4f,%.4f)\n",
		xyz[0],xyz[1],xyz[2],hpr[0],hpr[1],hpr[2]);
	break;
      }
      case 'w': case 'W':
	writeframes ^= 1;
	if (writeframes) printf ("Now writing frames to PPM files\n");
	break;
      }
    }
    last_key_pressed = key;		// a kludgy place to put this...
  }
  return;

  case KeyRelease: {
    // hmmmm...
  }
  return;

  case ClientMessage:
    if (event.xclient.message_type == wm_protocols_atom &&
	event.xclient.format == 32 &&
	Atom(event.xclient.data.l[0]) == wm_delete_window_atom) {
      run = 0;
      return;
    }
    return;

  case ConfigureNotify:
    width = event.xconfigure.width;
    height = event.xconfigure.height;
    return;
  }
}

// return the index of the highest bit
static int getHighBitIndex (unsigned int x)
{
  int i = 0;
  while (x) {
    i++;
    x >>= 1;
  }
  return i-1;
}

// shift x left by i, where i can be positive or negative
#define SHIFTL(x,i) (((i) >= 0) ? ((x) << (i)) : ((x) >> (-i)))

static void captureFrame (int num)
{
  fprintf (stderr,"capturing frame %04d\n",num);

  char s[100];
  sprintf (s,"frame/frame%04d.ppm",num);
  FILE *f = fopen (s,"wb");
  if (!f) dsError ("can't open \"%s\" for writing",s);
  fprintf (f,"P6\n%d %d\n255\n",width,height);
  XImage *image = XGetImage (display,win,0,0,width,height,~0,ZPixmap);

  int rshift = 7 - getHighBitIndex (image->red_mask);
  int gshift = 7 - getHighBitIndex (image->green_mask);
  int bshift = 7 - getHighBitIndex (image->blue_mask);

  for (int y=0; y<height; y++) {
    for (int x=0; x<width; x++) {
      unsigned long pixel = XGetPixel (image,x,y);
      unsigned char b[3];
      b[0] = SHIFTL(pixel & image->red_mask,rshift);
      b[1] = SHIFTL(pixel & image->green_mask,gshift);
      b[2] = SHIFTL(pixel & image->blue_mask,bshift);
      fwrite (b,3,1,f);
    }
  }
  fclose (f);
  XDestroyImage (image);
}

void dsPlatformSimLoop (int window_width, int window_height, dsFunctions *fn,
			int initial_pause)
{
  pause = initial_pause;
  createMainWindow (window_width, window_height);
  glXMakeCurrent (display,win,glx_context);

  dsStartGraphics (window_width,window_height,fn);

  fprintf (stderr,
	   "\n"
	   "Simulation test environment v%d.%02d\n"
	   "   Ctrl-P : pause / unpause (or say `-pause' on command line).\n"
	   "   Ctrl-O : single step when paused.\n"
	   "   Ctrl-T : toggle textures (or say `-notex' on command line).\n"
	   "   Ctrl-S : toggle shadows (or say `-noshadow' on command line).\n"
	   "   Ctrl-V : print current viewpoint coordinates (x,y,z,h,p,r).\n"
	   "   Ctrl-W : write frames to ppm files: frame/frameNNN.ppm\n"
	   "   Ctrl-X : exit.\n"
	   "\n"
	   "Change the camera position by clicking + dragging in the window.\n"
	   "   Left button - pan and tilt.\n"
	   "   Right button - forward and sideways.\n"
	   "   Left + Right button (or middle button) - sideways and up.\n"
	   "\n",DS_VERSION >> 8,DS_VERSION & 0xff);

  if (fn->start) fn->start();

  int frame = 1;
  run = 1;
  while (run) {
    // read in and process all pending events for the main window
    XEvent event;
    while (run && XPending (display)) {
      XNextEvent (display,&event);
      handleEvent (event,fn);
    }

    dsDrawFrame (width,height,fn,pause && !singlestep);
    singlestep = 0;

    glFlush();
    glXSwapBuffers (display,win);
    XSync (display,0);

    // capture frames if necessary
    if (pause==0 && writeframes) {
      captureFrame (frame);
      frame++;
    }
  };

  if (fn->stop) fn->stop();
  dsStopGraphics();

  destroyMainWindow();
}

extern "C" void dsStop()
{
  run = 0;
}
<commit_msg>fixes from d redgrave<commit_after>/*************************************************************************
 *                                                                       *
 * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith.       *
 * All rights reserved.  Email: russ@q12.org   Web: www.q12.org          *
 *                                                                       *
 * This library is free software; you can redistribute it and/or         *
 * modify it under the terms of EITHER:                                  *
 *   (1) The GNU Lesser General Public License as published by the Free  *
 *       Software Foundation; either version 2.1 of the License, or (at  *
 *       your option) any later version. The text of the GNU Lesser      *
 *       General Public License is included with this library in the     *
 *       file LICENSE.TXT.                                               *
 *   (2) The BSD-style license that is included with this library in     *
 *       the file LICENSE-BSD.TXT.                                       *
 *                                                                       *
 * This library is distributed in the hope that it will be useful,       *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files    *
 * LICENSE.TXT and LICENSE-BSD.TXT for more details.                     *
 *                                                                       *
 *************************************************************************/

// main window and event handling for X11

#include <ode/config.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include <GL/glx.h>

#include <drawstuff/drawstuff.h>
#include <drawstuff/version.h>
#include "internal.h"

//***************************************************************************
// error handling for unix

static void printMessage (char *msg1, char *msg2, va_list ap)
{
  fflush (stderr);
  fflush (stdout);
  fprintf (stderr,"\n%s: ",msg1);
  vfprintf (stderr,msg2,ap);
  fprintf (stderr,"\n");
  fflush (stderr);
}

extern "C" void dsError (char *msg, ...)
{
  va_list ap;
  va_start (ap,msg);
  printMessage ("Error",msg,ap);
  exit (1);
}

extern "C" void dsDebug (char *msg, ...)
{
  va_list ap;
  va_start (ap,msg);
  printMessage ("INTERNAL ERROR",msg,ap);
  // *((char *)0) = 0;	 ... commit SEGVicide ?
  abort();
}

extern "C" void dsPrint (char *msg, ...)
{
  va_list ap;
  va_start (ap,msg);
  vprintf (msg,ap);
}

//***************************************************************************
// openGL window

// X11 display info
static Display *display=0;
static int screen=0;
static XVisualInfo *visual=0;		// best visual for openGL
static Colormap colormap=0;		// window's colormap
static Atom wm_protocols_atom = 0;
static Atom wm_delete_window_atom = 0;

// window and openGL
static Window win=0;			// X11 window, 0 if not initialized
static int width=0,height=0;		// window size
static GLXContext glx_context=0;	// openGL rendering context
static int last_key_pressed=0;		// last key pressed in the window
static int run=1;			// 1 if simulation running
static int pause=0;			// 1 if in `pause' mode
static int singlestep=0;		// 1 if single step key pressed
static int writeframes=0;		// 1 if frame files to be written

static void createMainWindow (int _width, int _height)
{
  // create X11 display connection
  display = XOpenDisplay (NULL);
  if (!display) dsError ("can not open X11 display");
  screen = DefaultScreen(display);

  // get GL visual
  static int attribList[] = {GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE,16,
			     GLX_RED_SIZE,4, GLX_GREEN_SIZE,4,
			     GLX_BLUE_SIZE,4, None};
  visual = glXChooseVisual (display,screen,attribList);
  if (!visual) dsError ("no good X11 visual found for OpenGL");

  // create colormap
  colormap = XCreateColormap (display,RootWindow(display,screen),
			      visual->visual,AllocNone);

  // initialize variables
  win = 0;
  width = _width;
  height = _height;
  glx_context = 0;
  last_key_pressed = 0;

  if (width < 1 || height < 1) dsDebug (0,"bad window width or height");

  // create the window
  XSetWindowAttributes attributes;
  attributes.background_pixel = BlackPixel(display,screen);
  attributes.colormap = colormap;
  attributes.event_mask = ButtonPressMask | ButtonReleaseMask |
    KeyPressMask | KeyReleaseMask | ButtonMotionMask | PointerMotionHintMask |
    StructureNotifyMask;
  win = XCreateWindow (display,RootWindow(display,screen),50,50,width,height,
		       0,visual->depth, InputOutput,visual->visual,
		       CWBackPixel | CWColormap | CWEventMask,&attributes);

  // associate a GLX context with the window
  glx_context = glXCreateContext (display,visual,0,GL_TRUE);
  if (!glx_context) dsError ("can't make an OpenGL context");

  // set the window title
  XTextProperty window_name;
  window_name.value = (unsigned char *) "Simulation";
  window_name.encoding = XA_STRING;
  window_name.format = 8;
  window_name.nitems = strlen((char *) window_name.value);
  XSetWMName (display,win,&window_name);

  // participate in the window manager 'delete yourself' protocol
  wm_protocols_atom = XInternAtom (display,"WM_PROTOCOLS",False);
  wm_delete_window_atom = XInternAtom (display,"WM_DELETE_WINDOW",False);
  if (XSetWMProtocols (display,win,&wm_delete_window_atom,1)==0)
    dsError ("XSetWMProtocols() call failed");

  // pop up the window
  XMapWindow (display,win);
  XSync (display,win);
}

static void destroyMainWindow()
{
  glXDestroyContext (display,glx_context);
  XDestroyWindow (display,win);
  XSync (display,0);
  display = 0;
  win = 0;
  glx_context = 0;
}

static void handleEvent (XEvent &event, dsFunctions *fn)
{
  static int mx=0,my=0; 	// mouse position
  static int mode = 0;		// mouse button bits

  switch (event.type) {

  case ButtonPress: {
    if (event.xbutton.button == Button1) mode |= 1;
    if (event.xbutton.button == Button2) mode |= 2;
    if (event.xbutton.button == Button3) mode |= 4;
    mx = event.xbutton.x;
    my = event.xbutton.y;
  }
  return;

  case ButtonRelease: {
    if (event.xbutton.button == Button1) mode &= (~1);
    if (event.xbutton.button == Button2) mode &= (~2);
    if (event.xbutton.button == Button3) mode &= (~4);
    mx = event.xbutton.x;
    my = event.xbutton.x;
  }
  return;

  case MotionNotify: {
    if (event.xmotion.is_hint) {
      Window root,child;
      unsigned int mask;
      XQueryPointer (display,win,&root,&child,&event.xbutton.x_root,
		     &event.xbutton.y_root,&event.xbutton.x,&event.xbutton.y,
		     &mask);
    }
    dsMotion (mode, event.xmotion.x - mx, event.xmotion.y - my);
    mx = event.xmotion.x;
    my = event.xmotion.y;
  }
  return;

  case KeyPress: {
    KeySym key;
    XLookupString (&event.xkey,NULL,0,&key,0);
    if ((event.xkey.state & ControlMask) == 0) {
      if (key >= ' ' && key <= 126 && fn->command) fn->command (key);
    }
    else if (event.xkey.state & ControlMask) {
      switch (key) {
      case 't': case 'T':
	dsSetTextures (dsGetTextures() ^ 1);
	break;
      case 's': case 'S':
	dsSetShadows (dsGetShadows() ^ 1);
	break;
      case 'x': case 'X':
	run = 0;
	break;
      case 'p': case 'P':
	pause ^= 1;
	singlestep = 0;
	break;
      case 'o': case 'O':
	if (pause) singlestep = 1;
	break;
      case 'v': case 'V': {
	float xyz[3],hpr[3];
	dsGetViewpoint (xyz,hpr);
	printf ("Viewpoint = (%.4f,%.4f,%.4f,%.4f,%.4f,%.4f)\n",
		xyz[0],xyz[1],xyz[2],hpr[0],hpr[1],hpr[2]);
	break;
      }
      case 'w': case 'W':
	writeframes ^= 1;
	if (writeframes) printf ("Now writing frames to PPM files\n");
	break;
      }
    }
    last_key_pressed = key;		// a kludgy place to put this...
  }
  return;

  case KeyRelease: {
    // hmmmm...
  }
  return;

  case ClientMessage:
    if (event.xclient.message_type == wm_protocols_atom &&
	event.xclient.format == 32 &&
	Atom(event.xclient.data.l[0]) == wm_delete_window_atom) {
      run = 0;
      return;
    }
    return;

  case ConfigureNotify:
    width = event.xconfigure.width;
    height = event.xconfigure.height;
    return;
  }
}

// return the index of the highest bit
static int getHighBitIndex (unsigned int x)
{
  int i = 0;
  while (x) {
    i++;
    x >>= 1;
  }
  return i-1;
}

// shift x left by i, where i can be positive or negative
#define SHIFTL(x,i) (((i) >= 0) ? ((x) << (i)) : ((x) >> (-i)))

static void captureFrame (int num)
{
  fprintf (stderr,"capturing frame %04d\n",num);

  char s[100];
  sprintf (s,"frame/frame%04d.ppm",num);
  FILE *f = fopen (s,"wb");
  if (!f) dsError ("can't open \"%s\" for writing",s);
  fprintf (f,"P6\n%d %d\n255\n",width,height);
  XImage *image = XGetImage (display,win,0,0,width,height,~0,ZPixmap);

  int rshift = 7 - getHighBitIndex (image->red_mask);
  int gshift = 7 - getHighBitIndex (image->green_mask);
  int bshift = 7 - getHighBitIndex (image->blue_mask);

  for (int y=0; y<height; y++) {
    for (int x=0; x<width; x++) {
      unsigned long pixel = XGetPixel (image,x,y);
      unsigned char b[3];
      b[0] = SHIFTL(pixel & image->red_mask,rshift);
      b[1] = SHIFTL(pixel & image->green_mask,gshift);
      b[2] = SHIFTL(pixel & image->blue_mask,bshift);
      fwrite (b,3,1,f);
    }
  }
  fclose (f);
  XDestroyImage (image);
}

void dsPlatformSimLoop (int window_width, int window_height, dsFunctions *fn,
			int initial_pause)
{
  pause = initial_pause;
  createMainWindow (window_width, window_height);
  glXMakeCurrent (display,win,glx_context);

  dsStartGraphics (window_width,window_height,fn);

  fprintf (stderr,
	   "\n"
	   "Simulation test environment v%d.%02d\n"
	   "   Ctrl-P : pause / unpause (or say `-pause' on command line).\n"
	   "   Ctrl-O : single step when paused.\n"
	   "   Ctrl-T : toggle textures (or say `-notex' on command line).\n"
	   "   Ctrl-S : toggle shadows (or say `-noshadow' on command line).\n"
	   "   Ctrl-V : print current viewpoint coordinates (x,y,z,h,p,r).\n"
	   "   Ctrl-W : write frames to ppm files: frame/frameNNN.ppm\n"
	   "   Ctrl-X : exit.\n"
	   "\n"
	   "Change the camera position by clicking + dragging in the window.\n"
	   "   Left button - pan and tilt.\n"
	   "   Right button - forward and sideways.\n"
	   "   Left + Right button (or middle button) - sideways and up.\n"
	   "\n",DS_VERSION >> 8,DS_VERSION & 0xff);

  if (fn->start) fn->start();

  int frame = 1;
  run = 1;
  while (run) {
    // read in and process all pending events for the main window
    XEvent event;
    while (run && XPending (display)) {
      XNextEvent (display,&event);
      handleEvent (event,fn);
    }

    dsDrawFrame (width,height,fn,pause && !singlestep);
    singlestep = 0;

    glFlush();
    glXSwapBuffers (display,win);
    XSync (display,0);

    // capture frames if necessary
    if (pause==0 && writeframes) {
      captureFrame (frame);
      frame++;
    }
  };

  if (fn->stop) fn->stop();
  dsStopGraphics();

  destroyMainWindow();
}

extern "C" void dsStop()
{
  run = 0;
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h"
#include "webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h"

namespace webrtc {
namespace acm2 {

#ifdef WEBRTC_CODEC_OPUS
namespace {
const CodecInst kDefaultOpusCodecInst = {105, "opus", 48000, 960, 1, 32000};
const int kCngPt = 255;  // Not using CNG in this test.
const int kRedPt = 255;  // Not using RED in this test.
}  // namespace

class AcmGenericCodecOpusTest : public ::testing::Test {
 protected:
  AcmGenericCodecOpusTest() {
    acm_codec_params_ = {kDefaultOpusCodecInst, false, false, VADNormal};
  }

  void CreateCodec() {
    codec_wrapper_.reset(new ACMGenericCodec(
        acm_codec_params_.codec_inst, kCngPt, kCngPt, kCngPt, kCngPt,
        false /* enable RED */, kRedPt));
    ASSERT_TRUE(codec_wrapper_);
    ASSERT_EQ(0, codec_wrapper_->InitEncoder(&acm_codec_params_, true));
  }

  const AudioEncoderOpus* GetAudioEncoderOpus() {
    const AudioEncoderOpus* ptr = static_cast<const AudioEncoderOpus*>(
        codec_wrapper_->GetAudioEncoder());
    EXPECT_NE(nullptr, ptr);
    return ptr;
  }
  WebRtcACMCodecParams acm_codec_params_;
  rtc::scoped_ptr<ACMGenericCodec> codec_wrapper_;
};

TEST_F(AcmGenericCodecOpusTest, DefaultApplicationModeMono) {
  acm_codec_params_.codec_inst.channels = 1;
  CreateCodec();
  EXPECT_EQ(AudioEncoderOpus::kVoip, GetAudioEncoderOpus()->application());
}

TEST_F(AcmGenericCodecOpusTest, DefaultApplicationModeStereo) {
  acm_codec_params_.codec_inst.channels = 2;
  CreateCodec();
  EXPECT_EQ(AudioEncoderOpus::kAudio, GetAudioEncoderOpus()->application());
}

TEST_F(AcmGenericCodecOpusTest, ChangeApplicationMode) {
  // Create a stereo encoder.
  acm_codec_params_.codec_inst.channels = 2;
  CreateCodec();
  // Verify that the mode is kAudio.
  const AudioEncoderOpus* opus_ptr = GetAudioEncoderOpus();
  EXPECT_EQ(AudioEncoderOpus::kAudio, opus_ptr->application());

  // Change mode.
  EXPECT_EQ(0, codec_wrapper_->SetOpusApplication(kVoip, false));
  // Verify that the AudioEncoder object was changed.
  EXPECT_NE(opus_ptr, GetAudioEncoderOpus());
  EXPECT_EQ(AudioEncoderOpus::kVoip, GetAudioEncoderOpus()->application());
}

TEST_F(AcmGenericCodecOpusTest, ResetWontChangeApplicationMode) {
  // Create a stereo encoder.
  acm_codec_params_.codec_inst.channels = 2;
  CreateCodec();
  const AudioEncoderOpus* opus_ptr = GetAudioEncoderOpus();
  // Verify that the mode is kAudio.
  EXPECT_EQ(AudioEncoderOpus::kAudio, opus_ptr->application());

  // Trigger a reset.
  ASSERT_EQ(0, codec_wrapper_->InitEncoder(&acm_codec_params_, false));
  // Verify that the AudioEncoder object changed.
  EXPECT_NE(opus_ptr, GetAudioEncoderOpus());
  // Verify that the mode is still kAudio.
  EXPECT_EQ(AudioEncoderOpus::kAudio, GetAudioEncoderOpus()->application());

  // Now change to kVoip.
  EXPECT_EQ(0, codec_wrapper_->SetOpusApplication(kVoip, false));
  EXPECT_EQ(AudioEncoderOpus::kVoip, GetAudioEncoderOpus()->application());

  opus_ptr = GetAudioEncoderOpus();
  // Trigger a reset again.
  ASSERT_EQ(0, codec_wrapper_->InitEncoder(&acm_codec_params_, false));
  // Verify that the AudioEncoder object changed.
  EXPECT_NE(opus_ptr, GetAudioEncoderOpus());
  // Verify that the mode is still kVoip.
  EXPECT_EQ(AudioEncoderOpus::kVoip, GetAudioEncoderOpus()->application());
}

TEST_F(AcmGenericCodecOpusTest, ToggleDtx) {
  // Create a stereo encoder.
  acm_codec_params_.codec_inst.channels = 2;
  CreateCodec();
  // Verify that the mode is still kAudio.
  EXPECT_EQ(AudioEncoderOpus::kAudio, GetAudioEncoderOpus()->application());

  // DTX is not allowed in audio mode, if mode forcing flag is false.
  EXPECT_EQ(-1, codec_wrapper_->EnableOpusDtx(false));
  EXPECT_EQ(AudioEncoderOpus::kAudio, GetAudioEncoderOpus()->application());

  // DTX will be on, if mode forcing flag is true. Then application mode is
  // switched to kVoip.
  EXPECT_EQ(0, codec_wrapper_->EnableOpusDtx(true));
  EXPECT_EQ(AudioEncoderOpus::kVoip, GetAudioEncoderOpus()->application());

  // Audio mode is not allowed when DTX is on, and DTX forcing flag is false.
  EXPECT_EQ(-1, codec_wrapper_->SetOpusApplication(kAudio, false));
  EXPECT_EQ(true, GetAudioEncoderOpus()->dtx_enabled());

  // Audio mode will be set, if DTX forcing flag is true. Then DTX is switched
  // off.
  EXPECT_EQ(0, codec_wrapper_->SetOpusApplication(kAudio, true));
  EXPECT_EQ(false, GetAudioEncoderOpus()->dtx_enabled());

  // Now we set VOIP mode. The DTX forcing flag has no effect.
  EXPECT_EQ(0, codec_wrapper_->SetOpusApplication(kVoip, true));
  EXPECT_EQ(false, GetAudioEncoderOpus()->dtx_enabled());

  // In VOIP mode, we can enable DTX with mode forcing flag being false.
  EXPECT_EQ(0, codec_wrapper_->EnableOpusDtx(false));

  // Turn off DTX.
  EXPECT_EQ(0, codec_wrapper_->DisableOpusDtx());

  // When DTX is off, we can set Audio mode with DTX forcing flag being false.
  EXPECT_EQ(0, codec_wrapper_->SetOpusApplication(kAudio, false));
}
#endif  // WEBRTC_CODEC_OPUS

}  // namespace acm2
}  // namespace webrtc
<commit_msg>Fixing r8698.<commit_after>/*
 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h"
#include "webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h"

namespace webrtc {
namespace acm2 {

#ifdef WEBRTC_CODEC_OPUS
namespace {
const CodecInst kDefaultOpusCodecInst = {105, "opus", 48000, 960, 1, 32000};
const int kCngPt = 255;  // Not using CNG in this test.
const int kRedPt = 255;  // Not using RED in this test.
}  // namespace

class AcmGenericCodecOpusTest : public ::testing::Test {
 protected:
  AcmGenericCodecOpusTest() {
    acm_codec_params_ = {kDefaultOpusCodecInst, false, false, VADNormal};
  }

  void CreateCodec() {
    codec_wrapper_.reset(new ACMGenericCodec(
        acm_codec_params_.codec_inst, kCngPt, kCngPt, kCngPt, kCngPt,
        false /* enable RED */, kRedPt));
    ASSERT_TRUE(codec_wrapper_);
    ASSERT_EQ(0, codec_wrapper_->InitEncoder(&acm_codec_params_, true));
  }

  const AudioEncoderOpus* GetAudioEncoderOpus() {
    const AudioEncoderOpus* ptr = static_cast<const AudioEncoderOpus*>(
        codec_wrapper_->GetAudioEncoder());
    EXPECT_NE(nullptr, ptr);
    return ptr;
  }
  WebRtcACMCodecParams acm_codec_params_;
  rtc::scoped_ptr<ACMGenericCodec> codec_wrapper_;
};

TEST_F(AcmGenericCodecOpusTest, DefaultApplicationModeMono) {
  acm_codec_params_.codec_inst.channels = 1;
  CreateCodec();
  EXPECT_EQ(AudioEncoderOpus::kVoip, GetAudioEncoderOpus()->application());
}

TEST_F(AcmGenericCodecOpusTest, DefaultApplicationModeStereo) {
  acm_codec_params_.codec_inst.channels = 2;
  CreateCodec();
  EXPECT_EQ(AudioEncoderOpus::kAudio, GetAudioEncoderOpus()->application());
}

TEST_F(AcmGenericCodecOpusTest, ChangeApplicationMode) {
  // Create a stereo encoder.
  acm_codec_params_.codec_inst.channels = 2;
  CreateCodec();
  // Verify that the mode is kAudio.
  const AudioEncoderOpus* opus_ptr = GetAudioEncoderOpus();
  EXPECT_EQ(AudioEncoderOpus::kAudio, opus_ptr->application());

  // Change mode.
  EXPECT_EQ(0, codec_wrapper_->SetOpusApplication(kVoip, false));
  // Verify that the AudioEncoder object was changed.
  EXPECT_NE(opus_ptr, GetAudioEncoderOpus());
  EXPECT_EQ(AudioEncoderOpus::kVoip, GetAudioEncoderOpus()->application());
}

TEST_F(AcmGenericCodecOpusTest, ResetWontChangeApplicationMode) {
  // Create a stereo encoder.
  acm_codec_params_.codec_inst.channels = 2;
  CreateCodec();
  const AudioEncoderOpus* opus_ptr = GetAudioEncoderOpus();
  // Verify that the mode is kAudio.
  EXPECT_EQ(AudioEncoderOpus::kAudio, opus_ptr->application());

  // Trigger a reset.
  ASSERT_EQ(0, codec_wrapper_->InitEncoder(&acm_codec_params_, false));
  // Verify that the AudioEncoder object changed.
  EXPECT_NE(opus_ptr, GetAudioEncoderOpus());
  // Verify that the mode is still kAudio.
  EXPECT_EQ(AudioEncoderOpus::kAudio, GetAudioEncoderOpus()->application());

  // Now change to kVoip.
  EXPECT_EQ(0, codec_wrapper_->SetOpusApplication(kVoip, false));
  EXPECT_EQ(AudioEncoderOpus::kVoip, GetAudioEncoderOpus()->application());

  opus_ptr = GetAudioEncoderOpus();
  // Trigger a reset again.
  ASSERT_EQ(0, codec_wrapper_->InitEncoder(&acm_codec_params_, false));
  // Verify that the AudioEncoder object changed.
  EXPECT_NE(opus_ptr, GetAudioEncoderOpus());
  // Verify that the mode is still kVoip.
  EXPECT_EQ(AudioEncoderOpus::kVoip, GetAudioEncoderOpus()->application());
}

TEST_F(AcmGenericCodecOpusTest, ToggleDtx) {
  // Create a stereo encoder.
  acm_codec_params_.codec_inst.channels = 2;
  CreateCodec();
  // Verify that the mode is still kAudio.
  EXPECT_EQ(AudioEncoderOpus::kAudio, GetAudioEncoderOpus()->application());

  // DTX is not allowed in audio mode, if mode forcing flag is false.
  EXPECT_EQ(-1, codec_wrapper_->EnableOpusDtx(false));
  EXPECT_EQ(AudioEncoderOpus::kAudio, GetAudioEncoderOpus()->application());

  // DTX will be on, if mode forcing flag is true. Then application mode is
  // switched to kVoip.
  EXPECT_EQ(0, codec_wrapper_->EnableOpusDtx(true));
  EXPECT_EQ(AudioEncoderOpus::kVoip, GetAudioEncoderOpus()->application());

  // Audio mode is not allowed when DTX is on, and DTX forcing flag is false.
  EXPECT_EQ(-1, codec_wrapper_->SetOpusApplication(kAudio, false));
  EXPECT_TRUE(GetAudioEncoderOpus()->dtx_enabled());

  // Audio mode will be set, if DTX forcing flag is true. Then DTX is switched
  // off.
  EXPECT_EQ(0, codec_wrapper_->SetOpusApplication(kAudio, true));
  EXPECT_FALSE(GetAudioEncoderOpus()->dtx_enabled());

  // Now we set VOIP mode. The DTX forcing flag has no effect.
  EXPECT_EQ(0, codec_wrapper_->SetOpusApplication(kVoip, true));
  EXPECT_FALSE(GetAudioEncoderOpus()->dtx_enabled());

  // In VOIP mode, we can enable DTX with mode forcing flag being false.
  EXPECT_EQ(0, codec_wrapper_->EnableOpusDtx(false));

  // Turn off DTX.
  EXPECT_EQ(0, codec_wrapper_->DisableOpusDtx());

  // When DTX is off, we can set Audio mode with DTX forcing flag being false.
  EXPECT_EQ(0, codec_wrapper_->SetOpusApplication(kAudio, false));
}
#endif  // WEBRTC_CODEC_OPUS

}  // namespace acm2
}  // namespace webrtc
<|endoftext|>


<commit_before>// Copyright 2018, OpenCensus Authors
//
// 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.

#include "opencensus/exporters/trace/zipkin/zipkin_exporter.h"

#include <arpa/inet.h>
#include <ifaddrs.h>
#include <iostream>

#include <curl/curl.h>
#include <rapidjson/prettywriter.h>
#include <rapidjson/stringbuffer.h>
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "opencensus/trace/exporter/attribute_value.h"
#include "opencensus/trace/exporter/span_exporter.h"

namespace opencensus {
namespace exporters {
namespace trace {

namespace {

constexpr char kZipkinLib[] = "zipkin/2.0";
constexpr char ipv4_loopback[] = "127.0.0.1";
constexpr char ipv6_loopback[] = "::1";

std::string SerializeMessageEvent(
    const ::opencensus::trace::exporter::MessageEvent& event) {
  return absl::StrCat(
      event.type() == ::opencensus::trace::exporter::MessageEvent::Type::SENT
          ? "SENT"
          : "RECEIVED",
      "/", event.id(), "/", event.compressed_size());
}

std::string AttributeValueToString(
    const ::opencensus::trace::exporter::AttributeValue& value) {
  switch (value.type()) {
    case ::opencensus::trace::AttributeValueRef::Type::kString:
      return value.string_value();
      break;
    case ::opencensus::trace::AttributeValueRef::Type::kBool:
      return value.bool_value() ? "true" : "false";
      break;
    case ::opencensus::trace::AttributeValueRef::Type::kInt:
      return std::to_string(value.int_value());
      break;
  }
  ABSL_ASSERT(false && "Unknown AttributeValue type");
  return "";
}

std::string SerializeAnnotation(
    const ::opencensus::trace::exporter::Annotation& annotation) {
  std::string annotation_str(annotation.description());
  if (!annotation.attributes().empty()) {
    absl::StrAppend(&annotation_str, " (");
    size_t count = 0;
    for (const auto& attribute : annotation.attributes()) {
      absl::StrAppend(&annotation_str, attribute.first, ":",
                      AttributeValueToString(attribute.second));

      if (++count < annotation.attributes().size()) {
        absl::StrAppend(&annotation_str, ", ");
      }
    }
    absl::StrAppend(&annotation_str, ")");
  }
  return annotation_str;
}

void SerializeJson(const ::opencensus::trace::exporter::SpanData& span,
                   const ZipkinExporterOptions::Service& service,
                   rapidjson::Writer<rapidjson::StringBuffer>* writer) {
  writer->StartObject();

  writer->Key("name");
  writer->String(std::string(span.name()));

  writer->Key("traceId");
  writer->String(span.context().trace_id().ToHex());

  if (span.parent_span_id().IsValid()) {
    writer->Key("parentId");
    writer->String(span.parent_span_id().ToHex());
  }

  writer->Key("id");
  writer->String(span.context().span_id().ToHex());

  // Write endpoint.  OpenCensus does not support this by default.
  writer->Key("localEndpoint");
  writer->StartObject();
  writer->Key("serviceName");
  writer->String(service.service_name);
  if (service.af_type == ZipkinExporterOptions::AddressFamily::kIpv6) {
    writer->Key("ipv6");
  } else {
    writer->Key("ipv4");
  }
  writer->String(service.ip_address);
  writer->EndObject();

  if (!span.annotations().events().empty()) {
    writer->Key("annotations");
    writer->StartArray();
    for (const auto& annotation : span.annotations().events()) {
      writer->StartObject();
      writer->Key("timestamp");
      writer->Int64(absl::ToUnixMicros(annotation.timestamp()));
      writer->Key("value");
      writer->String(SerializeAnnotation(annotation.event()));
      writer->EndObject();
    }
    writer->EndArray(span.annotations().events().size());
  }

  if (!span.message_events().events().empty()) {
    writer->Key("annotations");
    writer->StartArray();
    for (const auto& event : span.message_events().events()) {
      writer->StartObject();
      writer->Key("timestamp");
      writer->Int64(absl::ToUnixMicros(event.timestamp()));
      writer->Key("value");
      writer->String(SerializeMessageEvent(event.event()));
      writer->EndObject();
    }
    writer->EndArray(span.message_events().events().size());
  }

  if (!span.attributes().empty()) {
    writer->Key("tags");
    writer->StartObject();
    for (const auto& attribute : span.attributes()) {
      writer->String(attribute.first);
      writer->String(AttributeValueToString(attribute.second));
    }
    writer->EndObject();
  }

  writer->Key("timestamp");
  writer->Int64(absl::ToUnixMicros(span.start_time()));

  writer->Key("duration");
  writer->Int64(absl::ToInt64Microseconds(span.end_time() - span.start_time()));

  writer->EndObject();
}

// JSON encoding
std::string EncodeJson(
    const std::vector<::opencensus::trace::exporter::SpanData>& spans,
    const ZipkinExporterOptions::Service& service) {
  rapidjson::StringBuffer buffer;
  rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

  writer.StartArray();
  for (const auto& span : spans) {
    SerializeJson(span, service, &writer);
  }
  writer.EndArray();
  return buffer.GetString();
}

std::string GetIpAddress(ZipkinExporterOptions::AddressFamily af_type) {
  struct ifaddrs* if_address_list;
  struct ifaddrs* if_address;

  getifaddrs(&if_address_list);
  for (if_address = if_address_list; if_address != nullptr;
       if_address = if_address->ifa_next) {
    if (if_address->ifa_addr == nullptr) {
      continue;
    }
    if (if_address->ifa_addr->sa_family == AF_INET) {
      if (af_type != ZipkinExporterOptions::AddressFamily::kIpv4) continue;
      char address[INET_ADDRSTRLEN];
      inet_ntop(AF_INET,
                &(reinterpret_cast<struct sockaddr_in*>(if_address->ifa_addr)
                      ->sin_addr),
                address, INET_ADDRSTRLEN);
      std::string ipv4_address(address);
      if (ipv4_address.compare(ipv4_loopback) == 0)
        continue;
      else
        return ipv4_address;
    } else if (if_address->ifa_addr->sa_family == AF_INET6) {
      if (af_type != ZipkinExporterOptions::AddressFamily::kIpv6) continue;
      char address[INET6_ADDRSTRLEN];
      inet_ntop(AF_INET6,
                &(reinterpret_cast<struct sockaddr_in6*>(if_address->ifa_addr)
                      ->sin6_addr),
                address, INET6_ADDRSTRLEN);
      std::string ipv6_address(address);
      if (ipv6_address.compare(ipv6_loopback) == 0)
        continue;
      else
        return ipv6_address;
    }
  }

  if (af_type == ZipkinExporterOptions::AddressFamily::kIpv4)
    return ipv4_loopback;
  else
    return ipv6_loopback;
}

class CurlEnv {
 public:
  CurlEnv() { curl_global_init(CURL_GLOBAL_DEFAULT); }
  ~CurlEnv() { curl_global_cleanup(); }
};

CURLcode CurlSendMessage(const uint8_t* data,
                         const ZipkinExporterOptions& options, size_t size,
                         const struct curl_slist* headers, CURL* curl,
                         char* err_msg) {
  CURLcode res;

  if ((res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers)) != CURLE_OK) {
    // Failed to set curl header.
    return res;
  }
  if ((res = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, err_msg)) !=
      CURLE_OK) {
    // Failed to set curl error buffer.
    return res;
  }
  if ((res = curl_easy_setopt(curl, CURLOPT_URL, options.url.c_str())) !=
      CURLE_OK) {
    // Failed to set url.
    return res;
  }
  if ((res = curl_easy_setopt(curl, CURLOPT_USERAGENT, kZipkinLib)) !=
      CURLE_OK) {
    // Failed to set http user agent.
    return res;
  }
  if ((res = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, size)) != CURLE_OK) {
    // Failed to set http body size.
    return res;
  }
  if ((res = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data)) != CURLE_OK) {
    // Failed to set http body data.
    return res;
  }
  if ((res = curl_easy_setopt(
           curl, CURLOPT_CONNECTTIMEOUT,
           absl::ToInt64Milliseconds(options.connect_timeout))) != CURLE_OK) {
    // Failed to set connect timeout.
    return res;
  }
  if ((res = curl_easy_setopt(
           curl, CURLOPT_TIMEOUT_MS,
           absl::ToInt64Milliseconds(options.request_timeout))) != CURLE_OK) {
    // Failed to set request timeout.
    return res;
  }
  if ((res = curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1)) != CURLE_OK) {
    // Failed to disable signals.
    return res;
  }

  if (options.proxy.empty()) {
    if ((res = curl_easy_setopt(curl, CURLOPT_PROXY, options.proxy.c_str())) !=
        CURLE_OK) {
      // Failed to set proxy.
      return res;
    }

    if (options.http_proxy_tunnel) {
      if ((res = curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP)) !=
          CURLE_OK) {
        // Failed to set HTTP proxy type.
        return res;
      }
      if ((res = curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1)) !=
          CURLE_OK) {
        // Failed to set HTTP proxy tunnel.
        return res;
      }
    }
  }

  if (options.max_redirect_times > 0) {
    if ((res = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1)) != CURLE_OK) {
      // Failed to enable follow location.
      return res;
    }
    if ((res = curl_easy_setopt(curl, CURLOPT_MAXREDIRS,
                                options.max_redirect_times)) != CURLE_OK) {
      // Failed to set max redirect times.
      return res;
    }
  }

  // Sending HTTP request to url.
  res = curl_easy_perform(curl);

  return res;
}

}  // namespace

class ZipkinExportHandler
    : public ::opencensus::trace::exporter::SpanExporter::Handler {
 public:
  ZipkinExportHandler(const ZipkinExporterOptions& options)
      : options_(options) {}

  void Export(const std::vector<::opencensus::trace::exporter::SpanData>& spans)
      override;

  // Send HTTP message to zipkin endpoint using libcurl.
  void SendMessage(const std::string& msg, size_t size) const;

  ZipkinExporterOptions options_;
  ZipkinExporterOptions::Service service_;
};

void ZipkinExportHandler::SendMessage(const std::string& msg,
                                      size_t size) const {
  char err_msg[CURL_ERROR_SIZE] = {0};
  CURL* curl = curl_easy_init();
  struct curl_slist* headers = nullptr;

  if (!curl) {
    // Failed to create curl handle.
    return;
  }

  // This is required for the server to recognize that it is a json encoded
  // message.
  headers = curl_slist_append(headers, "Content-Type: application/json");
  CURLcode res = CurlSendMessage(reinterpret_cast<const uint8_t*>(msg.data()),
                                 options_, size, headers, curl, err_msg);
  if (res != CURLE_OK) {
    std::cerr << "curl error: " << curl_easy_strerror(res);
  }

  curl_slist_free_all(headers);
  curl_easy_cleanup(curl);
}

void ZipkinExportHandler::Export(
    const std::vector<::opencensus::trace::exporter::SpanData>& spans) {
  if (!spans.empty()) {
    std::string msg = EncodeJson(spans, service_);
    SendMessage(msg, msg.size());
  }
}

void ZipkinExporter::Register(const ZipkinExporterOptions& options) {
  // Initialize libcurl. This MUST only be done once per process.
  static CurlEnv* curl_lib ABSL_ATTRIBUTE_UNUSED = new CurlEnv();

  // Create new exporter.
  ZipkinExportHandler* handler = new ZipkinExportHandler(options);
  handler->service_.service_name = options.service_name;
  // Get IP address of current machine.
  handler->service_.af_type = options.af_type;
  handler->service_.ip_address = GetIpAddress(options.af_type);
  ::opencensus::trace::exporter::SpanExporter::RegisterHandler(
      absl::WrapUnique<::opencensus::trace::exporter::SpanExporter::Handler>(
          handler));
}

}  // namespace trace
}  // namespace exporters
}  // namespace opencensus
<commit_msg>Fix memory leaks in GetIpAddress() and CurlEnv. (#159)<commit_after>// Copyright 2018, OpenCensus Authors
//
// 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.

#include "opencensus/exporters/trace/zipkin/zipkin_exporter.h"

#include <arpa/inet.h>
#include <ifaddrs.h>
#include <iostream>

#include <curl/curl.h>
#include <rapidjson/prettywriter.h>
#include <rapidjson/stringbuffer.h>
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "opencensus/trace/exporter/attribute_value.h"
#include "opencensus/trace/exporter/span_exporter.h"

namespace opencensus {
namespace exporters {
namespace trace {

namespace {

constexpr char kZipkinLib[] = "zipkin/2.0";
constexpr char ipv4_loopback[] = "127.0.0.1";
constexpr char ipv6_loopback[] = "::1";

std::string SerializeMessageEvent(
    const ::opencensus::trace::exporter::MessageEvent& event) {
  return absl::StrCat(
      event.type() == ::opencensus::trace::exporter::MessageEvent::Type::SENT
          ? "SENT"
          : "RECEIVED",
      "/", event.id(), "/", event.compressed_size());
}

std::string AttributeValueToString(
    const ::opencensus::trace::exporter::AttributeValue& value) {
  switch (value.type()) {
    case ::opencensus::trace::AttributeValueRef::Type::kString:
      return value.string_value();
      break;
    case ::opencensus::trace::AttributeValueRef::Type::kBool:
      return value.bool_value() ? "true" : "false";
      break;
    case ::opencensus::trace::AttributeValueRef::Type::kInt:
      return std::to_string(value.int_value());
      break;
  }
  ABSL_ASSERT(false && "Unknown AttributeValue type");
  return "";
}

std::string SerializeAnnotation(
    const ::opencensus::trace::exporter::Annotation& annotation) {
  std::string annotation_str(annotation.description());
  if (!annotation.attributes().empty()) {
    absl::StrAppend(&annotation_str, " (");
    size_t count = 0;
    for (const auto& attribute : annotation.attributes()) {
      absl::StrAppend(&annotation_str, attribute.first, ":",
                      AttributeValueToString(attribute.second));

      if (++count < annotation.attributes().size()) {
        absl::StrAppend(&annotation_str, ", ");
      }
    }
    absl::StrAppend(&annotation_str, ")");
  }
  return annotation_str;
}

void SerializeJson(const ::opencensus::trace::exporter::SpanData& span,
                   const ZipkinExporterOptions::Service& service,
                   rapidjson::Writer<rapidjson::StringBuffer>* writer) {
  writer->StartObject();

  writer->Key("name");
  writer->String(std::string(span.name()));

  writer->Key("traceId");
  writer->String(span.context().trace_id().ToHex());

  if (span.parent_span_id().IsValid()) {
    writer->Key("parentId");
    writer->String(span.parent_span_id().ToHex());
  }

  writer->Key("id");
  writer->String(span.context().span_id().ToHex());

  // Write endpoint.  OpenCensus does not support this by default.
  writer->Key("localEndpoint");
  writer->StartObject();
  writer->Key("serviceName");
  writer->String(service.service_name);
  if (service.af_type == ZipkinExporterOptions::AddressFamily::kIpv6) {
    writer->Key("ipv6");
  } else {
    writer->Key("ipv4");
  }
  writer->String(service.ip_address);
  writer->EndObject();

  if (!span.annotations().events().empty()) {
    writer->Key("annotations");
    writer->StartArray();
    for (const auto& annotation : span.annotations().events()) {
      writer->StartObject();
      writer->Key("timestamp");
      writer->Int64(absl::ToUnixMicros(annotation.timestamp()));
      writer->Key("value");
      writer->String(SerializeAnnotation(annotation.event()));
      writer->EndObject();
    }
    writer->EndArray(span.annotations().events().size());
  }

  if (!span.message_events().events().empty()) {
    writer->Key("annotations");
    writer->StartArray();
    for (const auto& event : span.message_events().events()) {
      writer->StartObject();
      writer->Key("timestamp");
      writer->Int64(absl::ToUnixMicros(event.timestamp()));
      writer->Key("value");
      writer->String(SerializeMessageEvent(event.event()));
      writer->EndObject();
    }
    writer->EndArray(span.message_events().events().size());
  }

  if (!span.attributes().empty()) {
    writer->Key("tags");
    writer->StartObject();
    for (const auto& attribute : span.attributes()) {
      writer->String(attribute.first);
      writer->String(AttributeValueToString(attribute.second));
    }
    writer->EndObject();
  }

  writer->Key("timestamp");
  writer->Int64(absl::ToUnixMicros(span.start_time()));

  writer->Key("duration");
  writer->Int64(absl::ToInt64Microseconds(span.end_time() - span.start_time()));

  writer->EndObject();
}

std::string EncodeJson(
    const std::vector<::opencensus::trace::exporter::SpanData>& spans,
    const ZipkinExporterOptions::Service& service) {
  rapidjson::StringBuffer buffer;
  rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

  writer.StartArray();
  for (const auto& span : spans) {
    SerializeJson(span, service, &writer);
  }
  writer.EndArray();
  return buffer.GetString();
}

std::string GetIpAddressHelper(ZipkinExporterOptions::AddressFamily af_type,
                               ifaddrs* ifaddr_list) {
  for (ifaddrs* if_address = ifaddr_list; if_address != nullptr;
       if_address = if_address->ifa_next) {
    if (if_address->ifa_addr == nullptr) {
      continue;
    }
    if (if_address->ifa_addr->sa_family == AF_INET) {
      if (af_type != ZipkinExporterOptions::AddressFamily::kIpv4) continue;
      char address[INET_ADDRSTRLEN];
      inet_ntop(AF_INET,
                &(reinterpret_cast<struct sockaddr_in*>(if_address->ifa_addr)
                      ->sin_addr),
                address, INET_ADDRSTRLEN);
      std::string ipv4_address(address);
      if (ipv4_address.compare(ipv4_loopback) == 0)
        continue;
      else
        return ipv4_address;
    } else if (if_address->ifa_addr->sa_family == AF_INET6) {
      if (af_type != ZipkinExporterOptions::AddressFamily::kIpv6) continue;
      char address[INET6_ADDRSTRLEN];
      inet_ntop(AF_INET6,
                &(reinterpret_cast<struct sockaddr_in6*>(if_address->ifa_addr)
                      ->sin6_addr),
                address, INET6_ADDRSTRLEN);
      std::string ipv6_address(address);
      if (ipv6_address.compare(ipv6_loopback) == 0)
        continue;
      else
        return ipv6_address;
    }
  }

  if (af_type == ZipkinExporterOptions::AddressFamily::kIpv4)
    return ipv4_loopback;
  else
    return ipv6_loopback;
}

std::string GetIpAddress(ZipkinExporterOptions::AddressFamily af_type) {
  ifaddrs* ifaddr;
  getifaddrs(&ifaddr);
  std::string out = GetIpAddressHelper(af_type, ifaddr);
  freeifaddrs(ifaddr);
  return out;
}

class CurlEnv {
 public:
  static CurlEnv* Get();

 private:
  CurlEnv() { curl_global_init(CURL_GLOBAL_DEFAULT); }
  ~CurlEnv() { curl_global_cleanup(); }
};

// static
CurlEnv* CurlEnv::Get() {
  static CurlEnv* g_curl_env = new CurlEnv;
  return g_curl_env;
}

CURLcode CurlSendMessage(const uint8_t* data,
                         const ZipkinExporterOptions& options, size_t size,
                         const struct curl_slist* headers, CURL* curl,
                         char* err_msg) {
  CURLcode res;

  if ((res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers)) != CURLE_OK) {
    // Failed to set curl header.
    return res;
  }
  if ((res = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, err_msg)) !=
      CURLE_OK) {
    // Failed to set curl error buffer.
    return res;
  }
  if ((res = curl_easy_setopt(curl, CURLOPT_URL, options.url.c_str())) !=
      CURLE_OK) {
    // Failed to set url.
    return res;
  }
  if ((res = curl_easy_setopt(curl, CURLOPT_USERAGENT, kZipkinLib)) !=
      CURLE_OK) {
    // Failed to set http user agent.
    return res;
  }
  if ((res = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, size)) != CURLE_OK) {
    // Failed to set http body size.
    return res;
  }
  if ((res = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data)) != CURLE_OK) {
    // Failed to set http body data.
    return res;
  }
  if ((res = curl_easy_setopt(
           curl, CURLOPT_CONNECTTIMEOUT,
           absl::ToInt64Milliseconds(options.connect_timeout))) != CURLE_OK) {
    // Failed to set connect timeout.
    return res;
  }
  if ((res = curl_easy_setopt(
           curl, CURLOPT_TIMEOUT_MS,
           absl::ToInt64Milliseconds(options.request_timeout))) != CURLE_OK) {
    // Failed to set request timeout.
    return res;
  }
  if ((res = curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1)) != CURLE_OK) {
    // Failed to disable signals.
    return res;
  }

  if (options.proxy.empty()) {
    if ((res = curl_easy_setopt(curl, CURLOPT_PROXY, options.proxy.c_str())) !=
        CURLE_OK) {
      // Failed to set proxy.
      return res;
    }

    if (options.http_proxy_tunnel) {
      if ((res = curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP)) !=
          CURLE_OK) {
        // Failed to set HTTP proxy type.
        return res;
      }
      if ((res = curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1)) !=
          CURLE_OK) {
        // Failed to set HTTP proxy tunnel.
        return res;
      }
    }
  }

  if (options.max_redirect_times > 0) {
    if ((res = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1)) != CURLE_OK) {
      // Failed to enable follow location.
      return res;
    }
    if ((res = curl_easy_setopt(curl, CURLOPT_MAXREDIRS,
                                options.max_redirect_times)) != CURLE_OK) {
      // Failed to set max redirect times.
      return res;
    }
  }

  // Sending HTTP request to url.
  res = curl_easy_perform(curl);

  return res;
}

class ZipkinExportHandler
    : public ::opencensus::trace::exporter::SpanExporter::Handler {
 public:
  ZipkinExportHandler(const ZipkinExporterOptions& options)
      : options_(options) {}

  void Export(const std::vector<::opencensus::trace::exporter::SpanData>& spans)
      override;

  // Send HTTP message to zipkin endpoint using libcurl.
  void SendMessage(const std::string& msg, size_t size) const;

  ZipkinExporterOptions options_;
  ZipkinExporterOptions::Service service_;
};

void ZipkinExportHandler::SendMessage(const std::string& msg,
                                      size_t size) const {
  char err_msg[CURL_ERROR_SIZE] = {0};
  CURL* curl = curl_easy_init();
  struct curl_slist* headers = nullptr;

  if (!curl) {
    std::cerr << "Failed to create curl handle.\n";
    return;
  }

  // This is required for the server to recognize that it is a json encoded
  // message.
  headers = curl_slist_append(headers, "Content-Type: application/json");
  CURLcode res = CurlSendMessage(reinterpret_cast<const uint8_t*>(msg.data()),
                                 options_, size, headers, curl, err_msg);
  if (res != CURLE_OK) {
    std::cerr << "curl error: " << curl_easy_strerror(res) << "\n";
  }

  curl_slist_free_all(headers);
  curl_easy_cleanup(curl);
}

void ZipkinExportHandler::Export(
    const std::vector<::opencensus::trace::exporter::SpanData>& spans) {
  if (!spans.empty()) {
    std::string msg = EncodeJson(spans, service_);
    SendMessage(msg, msg.size());
  }
}

}  // namespace

void ZipkinExporter::Register(const ZipkinExporterOptions& options) {
  // Initialize libcurl. This MUST only be done once per process.
  CurlEnv::Get();

  // Create new exporter.
  ZipkinExportHandler* handler = new ZipkinExportHandler(options);
  handler->service_.service_name = options.service_name;
  // Get IP address of current machine.
  handler->service_.af_type = options.af_type;
  handler->service_.ip_address = GetIpAddress(options.af_type);
  ::opencensus::trace::exporter::SpanExporter::RegisterHandler(
      absl::WrapUnique<::opencensus::trace::exporter::SpanExporter::Handler>(
          handler));
}

}  // namespace trace
}  // namespace exporters
}  // namespace opencensus
<|endoftext|>


<commit_before>/* ------------------------------------------------------------------
 * Copyright (C) 1998-2009 PacketVideo
 *
 * 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.
 * -------------------------------------------------------------------
 */
/****************************************************************************************
Portions of this file are derived from the following 3GPP standard:

    3GPP TS 26.073
    ANSI-C code for the Adaptive Multi-Rate (AMR) speech codec
    Available from http://www.3gpp.org

(C) 2004, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TTA, TTC)
Permission to distribute, modify and use this file under the standard license
terms listed above has been obtained from the copyright holder.
****************************************************************************************/
/*

 Filename: /audio/gsm_amr/c/src/l_extract.c

     Date: 09/07/2000

------------------------------------------------------------------------------
 REVISION HISTORY

 Description: Updated template. Changed function interface to pass in a
              pointer to overflow flag into the function instead of using a
              global flag. Changed names of function parameters for clarity.
              Removed inclusion of unwanted header files.

 Description:

------------------------------------------------------------------------------
*/

/*----------------------------------------------------------------------------
; INCLUDES
----------------------------------------------------------------------------*/
#include    "basic_op.h"

/*----------------------------------------------------------------------------
; MACROS
; [Define module specific macros here]
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
; DEFINES
; [Include all pre-processor statements here. Include conditional
; compile variables also.]
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
; LOCAL FUNCTION DEFINITIONS
; [List function prototypes here]
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
; LOCAL VARIABLE DEFINITIONS
; [Variable declaration - defined here and used outside this module]
----------------------------------------------------------------------------*/

/*
------------------------------------------------------------------------------
 FUNCTION NAME: L_extract
------------------------------------------------------------------------------
 INPUT AND OUTPUT DEFINITIONS

 Inputs:
	L_var = 32 bit signed integer (Word32) whose value falls
	       in the range : 0x8000 0000 <= L_32 <= 0x7fff ffff.

    pL_var_hi =  pointer to the most significant word of L_var (Word16).

    pL_var_lo =  pointer to the least significant word of L_var shifted
              to the left by 1 (Word16).

    pOverflow = pointer to overflow (Flag)

 Outputs:
    pOverflow -> 1 if the 32 bit add operation resulted in overflow
	pL_var_hi -> MS word of L_32.
	pL_var_lo -> LS word of L_32 shifted left by 1.

 Returns:
    None

 Global Variables Used:
    None

 Local Variables Needed:
    None

------------------------------------------------------------------------------
 FUNCTION DESCRIPTION

 This function extracts two 16-bit double precision format (DPF) numbers
 from a 32-bit integer. The MS word of L_var will be stored in the location
 pointed to by pL_var_hi and the shifted LS word of L_var will be stored in
 the location pointed to by pL_var_lo.

------------------------------------------------------------------------------
 REQUIREMENTS

 None

------------------------------------------------------------------------------
 REFERENCES

 [1] L_extract() function in oper_32b.c,  UMTS GSM AMR speech codec, R99 -
 Version 3.2.0, March 2, 2001

------------------------------------------------------------------------------
 PSEUDO-CODE

------------------------------------------------------------------------------
 RESOURCES USED [optional]

 When the code is written for a specific target processor the
 the resources used should be documented below.

 HEAP MEMORY USED: x bytes

 STACK MEMORY USED: x bytes

 CLOCK CYCLES: (cycle count equation for this function) + (variable
                used to represent cycle count for each subroutine
                called)
     where: (cycle count variable) = cycle count for [subroutine
                                     name]

------------------------------------------------------------------------------
 CAUTION [optional]
 [State any special notes, constraints or cautions for users of this function]

------------------------------------------------------------------------------
*/

/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
void L_Extract(Word32 L_var,
               Word16 *pL_var_hi,
               Word16 *pL_var_lo,
               Flag   *pOverflow)
{

    Word32  temp;

    OSCL_UNUSED_ARG(pOverflow);

    temp = (L_var >> 16);

    *(pL_var_hi) = (Word16) temp;
    *(pL_var_lo) = (Word16)((L_var >> 1) - (temp << 15));

    return;
}
<commit_msg>Fix compiler warnings.<commit_after>/* ------------------------------------------------------------------
 * Copyright (C) 1998-2009 PacketVideo
 *
 * 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.
 * -------------------------------------------------------------------
 */
/****************************************************************************************
Portions of this file are derived from the following 3GPP standard:

    3GPP TS 26.073
    ANSI-C code for the Adaptive Multi-Rate (AMR) speech codec
    Available from http://www.3gpp.org

(C) 2004, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TTA, TTC)
Permission to distribute, modify and use this file under the standard license
terms listed above has been obtained from the copyright holder.
****************************************************************************************/
/*

 Filename: /audio/gsm_amr/c/src/l_extract.c

     Date: 09/07/2000

------------------------------------------------------------------------------
 REVISION HISTORY

 Description: Updated template. Changed function interface to pass in a
              pointer to overflow flag into the function instead of using a
              global flag. Changed names of function parameters for clarity.
              Removed inclusion of unwanted header files.

 Description:

------------------------------------------------------------------------------
*/

/*----------------------------------------------------------------------------
; INCLUDES
----------------------------------------------------------------------------*/
#include    "basic_op.h"

/*----------------------------------------------------------------------------
; MACROS
; [Define module specific macros here]
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
; DEFINES
; [Include all pre-processor statements here. Include conditional
; compile variables also.]
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
; LOCAL FUNCTION DEFINITIONS
; [List function prototypes here]
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
; LOCAL VARIABLE DEFINITIONS
; [Variable declaration - defined here and used outside this module]
----------------------------------------------------------------------------*/

/*
------------------------------------------------------------------------------
 FUNCTION NAME: L_extract
------------------------------------------------------------------------------
 INPUT AND OUTPUT DEFINITIONS

 Inputs:
	L_var = 32 bit signed integer (Word32) whose value falls
	       in the range : 0x8000 0000 <= L_32 <= 0x7fff ffff.

    pL_var_hi =  pointer to the most significant word of L_var (Word16).

    pL_var_lo =  pointer to the least significant word of L_var shifted
              to the left by 1 (Word16).

    pOverflow = pointer to overflow (Flag)

 Outputs:
    pOverflow -> 1 if the 32 bit add operation resulted in overflow
	pL_var_hi -> MS word of L_32.
	pL_var_lo -> LS word of L_32 shifted left by 1.

 Returns:
    None

 Global Variables Used:
    None

 Local Variables Needed:
    None

------------------------------------------------------------------------------
 FUNCTION DESCRIPTION

 This function extracts two 16-bit double precision format (DPF) numbers
 from a 32-bit integer. The MS word of L_var will be stored in the location
 pointed to by pL_var_hi and the shifted LS word of L_var will be stored in
 the location pointed to by pL_var_lo.

------------------------------------------------------------------------------
 REQUIREMENTS

 None

------------------------------------------------------------------------------
 REFERENCES

 [1] L_extract() function in oper_32b.c,  UMTS GSM AMR speech codec, R99 -
 Version 3.2.0, March 2, 2001

------------------------------------------------------------------------------
 PSEUDO-CODE

------------------------------------------------------------------------------
 RESOURCES USED [optional]

 When the code is written for a specific target processor the
 the resources used should be documented below.

 HEAP MEMORY USED: x bytes

 STACK MEMORY USED: x bytes

 CLOCK CYCLES: (cycle count equation for this function) + (variable
                used to represent cycle count for each subroutine
                called)
     where: (cycle count variable) = cycle count for [subroutine
                                     name]

------------------------------------------------------------------------------
 CAUTION [optional]
 [State any special notes, constraints or cautions for users of this function]

------------------------------------------------------------------------------
*/

/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
void L_Extract(Word32 L_var,
               Word16 *pL_var_hi,
               Word16 *pL_var_lo,
               Flag   *pOverflow)
{

    Word32  temp;

    (void)(pOverflow);

    temp = (L_var >> 16);

    *(pL_var_hi) = (Word16) temp;
    *(pL_var_lo) = (Word16)((L_var >> 1) - (temp << 15));

    return;
}
<|endoftext|>


<commit_before>//
//  Integer.cpp
//  Calculator
//
//  Created by Gavin Scheele on 3/28/14.
//  Copyright (c) 2014 Gavin Scheele. All rights reserved.
//

#include "Integer.h"
Integer::Integer(int value){
    this->type = "integer";
    this->value = value;
}
Integer::~Integer(){

}
int Integer::getValue() {
    return value;
}
void Integer::setValue(int n) {
    value = n;
}
Expression* Integer::add(Expression* a){
    if(a->type == "euler"){

    }else if(a->type == "exponential"){

    }else if(a->type == "integer"){

    }else if(a->type == "logarithm"){

    }else if(a->type == "nthRoot"){

    }else if(a->type == "pi"){

    }else if(a->type == "rational"){

    }else{
        cout << "type not recognized" << endl;
    }
    return this;
}
Expression* Integer::subtract(Expression* a){
    if(a->type == "euler"){

    }else if(a->type == "exponential"){

    }else if(a->type == "integer"){

    }else if(a->type == "logarithm"){

    }else if(a->type == "nthRoot"){

    }else if(a->type == "pi"){

    }else if(a->type == "rational"){

    }else{
        cout << "type not recognized" << endl;
    }
    return this;
}
Expression* Integer::multiply(Expression* a){
    if(a->type == "euler"){

    }else if(a->type == "exponential"){

    }else if(a->type == "integer"){

    }else if(a->type == "logarithm"){

    }else if(a->type == "nthRoot"){

    }else if(a->type == "pi"){

    }else if(a->type == "rational"){

    }else{
        cout << "type not recognized" << endl;
    }
    return this;
}
Expression* Integer::divide(Expression* a){
    if(a->type == "euler"){

    }else if(a->type == "exponential"){

    }else if(a->type == "integer"){

    }else if(a->type == "logarithm"){

    }else if(a->type == "nthRoot"){

    }else if(a->type == "pi"){

    }else if(a->type == "rational"){

    }else{
        cout << "type not recognized" << endl;
    }
    return this;
}
ostream& Integer::print(std::ostream& output) const{
    output << this->value;
    return output;
}

string Integer::toString() {
    string str = value;
    return str;
}
<commit_msg>Finished add, subtract, multiply, and divide<commit_after>//
//  Integer.cpp
//  Calculator
//
//  Created by Gavin Scheele on 3/28/14.
//  Copyright (c) 2014 Gavin Scheele. All rights reserved.
//

#include "Integer.h"
Integer::Integer(int value){
    this->type = "integer";
    this->value = value;
}
Integer::~Integer(){

}
int Integer::getValue() {
    return value;
}
void Integer::setValue(int n) {
    value = n;
}
Expression* Integer::add(Expression* a){
    if(a->type == "euler"){

    }else if(a->type == "exponential"){

    }else if(a->type == "integer"){
        Integer *b = (Integer *)a;
        this->value+=b->getValue;

    }else if(a->type == "logarithm"){

    }else if(a->type == "nthRoot"){

    }else if(a->type == "pi"){

    }else if(a->type == "rational"){
        Rational *b = (Rational *) a;
        b->setNumerator(b->getNumerator->add(this->multiply(b->getDenominator)));
        this = b;

    }else{
        cout << "type not recognized" << endl;
    }
    return this;
}
Expression* Integer::subtract(Expression* a){
    if(a->type == "euler"){

    }else if(a->type == "exponential"){

    }else if(a->type == "integer"){
        Integer *b = (Integer *)a;
        this->value-=b->getValue;

    }else if(a->type == "logarithm"){

    }else if(a->type == "nthRoot"){

    }else if(a->type == "pi"){

    }else if(a->type == "rational"){
        Rational *b = (Rational *) a;
        b->setNumerator(b->getNumerator->subtract(this->multiply(b->getDenominator)));
        this = b;

    }else{
        cout << "type not recognized" << endl;
    }
    return this;
}
Expression* Integer::multiply(Expression* a){
    if(a->type == "euler"){

    }else if(a->type == "exponential"){

    }else if(a->type == "integer"){
        Integer *b = (Integer *)a;
        this->value*=b->getValue;

    }else if(a->type == "logarithm"){

    }else if(a->type == "nthRoot"){

    }else if(a->type == "pi"){

    }else if(a->type == "rational"){
        Rational *b = (Rational *) a;
        b->setNumerator(b->getNumerator->multiply(this));
        this = b;

    }else{
        cout << "type not recognized" << endl;
    }
    return this;
}
Expression* Integer::divide(Expression* a){
    if(a->type == "euler"){

    }else if(a->type == "exponential"){

    }else if(a->type == "integer"){
        Integer *b = (Integer *)a;
        this->value/=b->getValue;

    }else if(a->type == "logarithm"){

    }else if(a->type == "nthRoot"){

    }else if(a->type == "pi"){

    }else if(a->type == "rational"){
        Rational *b = (Rational *) a;
        b->setDenominator(b->getDenominator->multiply(this));
        this = b;

    }else{
        cout << "type not recognized" << endl;
    }
    return this;
}
ostream& Integer::print(std::ostream& output) const{
    output << this->value;
    return output;
}

string Integer::toString() {
    string str = (string) value;
    return str;
}
<|endoftext|>


<commit_before>#include "kwm.h"

extern std::vector<window_info> WindowLst;
extern int CurrentSpace;

node_container LeftVerticalContainerSplit(screen_info *Screen, tree_node *Node)
{
    node_container LeftContainer;

    LeftContainer.X = Node->Container.X;
    LeftContainer.Y = Node->Container.Y;
    LeftContainer.Height = Node->Container.Height;

    if(DoesSpaceExistInMapOfScreen(Screen))
        LeftContainer.Width = (Node->Container.Width / 2) - (Screen->Space[CurrentSpace].VerticalGap / 2);
    else
        LeftContainer.Width = (Node->Container.Width / 2) - (Screen->VerticalGap / 2);

    return LeftContainer;
}

node_container RightVerticalContainerSplit(screen_info *Screen, tree_node *Node)
{
    node_container RightContainer;

    RightContainer.Y = Node->Container.Y;
    RightContainer.Height = Node->Container.Height;

    if(DoesSpaceExistInMapOfScreen(Screen))
    {
        RightContainer.X = Node->Container.X + (Node->Container.Width / 2) + (Screen->Space[CurrentSpace].VerticalGap / 2);
        RightContainer.Width = (Node->Container.Width / 2) - (Screen->Space[CurrentSpace].VerticalGap / 2);
    }
    else
    {
        RightContainer.X = Node->Container.X + (Node->Container.Width / 2) + (Screen->VerticalGap / 2);
        RightContainer.Width = (Node->Container.Width / 2) - (Screen->VerticalGap / 2);
    }

    return RightContainer;
}

node_container UpperHorizontalContainerSplit(screen_info *Screen, tree_node *Node)
{
    node_container UpperContainer;

    UpperContainer.X = Node->Container.X;
    UpperContainer.Y = Node->Container.Y;
    UpperContainer.Width = Node->Container.Width;

    if(DoesSpaceExistInMapOfScreen(Screen))
        UpperContainer.Height = (Node->Container.Height / 2) - (Screen->Space[CurrentSpace].HorizontalGap / 2);
    else
        UpperContainer.Height = (Node->Container.Height / 2) - (Screen->HorizontalGap / 2);

    return UpperContainer;
}

node_container LowerHorizontalContainerSplit(screen_info *Screen, tree_node *Node)
{
    node_container LowerContainer;

    LowerContainer.X = Node->Container.X;
    LowerContainer.Width = Node->Container.Width;

    if(DoesSpaceExistInMapOfScreen(Screen))
    {
        LowerContainer.Y = Node->Container.Y + (Node->Container.Height / 2) + (Screen->Space[CurrentSpace].HorizontalGap / 2);
        LowerContainer.Height = (Node->Container.Height / 2) - (Screen->Space[CurrentSpace].HorizontalGap / 2);
    }
    else
    {
        LowerContainer.Y = Node->Container.Y + (Node->Container.Height / 2) + (Screen->HorizontalGap / 2);
        LowerContainer.Height = (Node->Container.Height / 2) - (Screen->HorizontalGap / 2);
    }

    return LowerContainer;
}

void CreateNodeContainer(screen_info *Screen, tree_node *Node, int ContainerType)
{
    switch(ContainerType)
    {
        case 1:
        {
            Node->Container = LeftVerticalContainerSplit(Screen, Node->Parent);
        } break;
        case 2:
        {
            Node->Container = RightVerticalContainerSplit(Screen, Node->Parent);
        } break;
        case 3:
        {
            Node->Container = UpperHorizontalContainerSplit(Screen, Node->Parent);
        } break;
        case 4:
        {
            Node->Container = LowerHorizontalContainerSplit(Screen, Node->Parent);
        } break;
    }

    Node->SplitMode = 0;
    if(ContainerType != -1)
        Node->Container.Type = ContainerType;
}

void CreateNodeContainerPair(screen_info *Screen, tree_node *LeftNode, tree_node *RightNode, int SplitMode)
{
    if(SplitMode == 1)
    {
        CreateNodeContainer(Screen, LeftNode, 1);
        CreateNodeContainer(Screen, RightNode, 2);
    }
    else
    {
        CreateNodeContainer(Screen, LeftNode, 3);
        CreateNodeContainer(Screen, RightNode, 4);
    }
}

tree_node *CreateLeafNode(screen_info *Screen, tree_node *Parent, int WindowID, int ContainerType)
{
    tree_node *Leaf = (tree_node*) malloc(sizeof(tree_node));
    Leaf->Parent = Parent;
    Leaf->WindowID = WindowID;

    CreateNodeContainer(Screen, Leaf, ContainerType);

    Leaf->LeftChild = NULL;
    Leaf->RightChild = NULL;

    return Leaf;
}

tree_node *CreateRootNode()
{
    tree_node *RootNode = (tree_node*) malloc(sizeof(tree_node));
    std::memset(RootNode, '\0', sizeof(tree_node));

    RootNode->WindowID = -1;
    RootNode->Parent = NULL;
    RootNode->LeftChild = NULL;
    RootNode->RightChild = NULL;

    return RootNode;
}

void SetRootNodeContainer(screen_info *Screen, tree_node *Node)
{
    if(DoesSpaceExistInMapOfScreen(Screen))
    {
        Node->Container.X = Screen->X + Screen->Space[CurrentSpace].PaddingLeft;
        Node->Container.Y = Screen->Y + Screen->Space[CurrentSpace].PaddingTop;
        Node->Container.Width = Screen->Width - Screen->Space[CurrentSpace].PaddingLeft - Screen->Space[CurrentSpace].PaddingRight;
        Node->Container.Height = Screen->Height - Screen->Space[CurrentSpace].PaddingTop - Screen->Space[CurrentSpace].PaddingBottom;
    }
    else
    {
        Node->Container.X = Screen->X + Screen->PaddingLeft;
        Node->Container.Y = Screen->Y + Screen->PaddingTop;
        Node->Container.Width = Screen->Width - Screen->PaddingLeft - Screen->PaddingRight;
        Node->Container.Height = Screen->Height - Screen->PaddingTop - Screen->PaddingBottom;
    }

    Node->Container.Type = 0;
    Node->SplitMode = 0;
}

void CreateLeafNodePair(screen_info *Screen, tree_node *Parent, int LeftWindowID, int RightWindowID, int SplitMode)
{
    Parent->WindowID = -1;
    Parent->SplitMode = SplitMode;

    if(SplitMode == 1)
    {
        Parent->LeftChild = CreateLeafNode(Screen, Parent, LeftWindowID, 1);
        Parent->RightChild = CreateLeafNode(Screen, Parent, RightWindowID, 2);
    }
    else
    {
        Parent->LeftChild = CreateLeafNode(Screen, Parent, LeftWindowID, 3);
        Parent->RightChild = CreateLeafNode(Screen, Parent, RightWindowID, 4);
    }
}

bool IsLeafNode(tree_node *Node)
{
    return Node->LeftChild == NULL && Node->RightChild == NULL ? true : false;
}

tree_node *CreateTreeFromWindowIDList(screen_info *Screen, std::vector<window_info*> *WindowsPtr)
{
    std::vector<window_info*> &Windows = *WindowsPtr;
    tree_node *RootNode = CreateRootNode();
    SetRootNodeContainer(Screen, RootNode);

    if(Windows.size() > 1)
    {
        tree_node *Root = RootNode;
        int FirstIndex;
        bool FoundValidWindow = false;
        for(FirstIndex = 0; FirstIndex < Windows.size(); ++FirstIndex)
        {
            if(!IsWindowFloating(Windows[FirstIndex]->WID, NULL))
            {
                Root->WindowID = Windows[FirstIndex]->WID;
                FoundValidWindow = true;
                break;
            }
        }

        if(!FoundValidWindow)
        {
            free(RootNode);
            return NULL;
        }

        for(int WindowIndex = FirstIndex + 1; WindowIndex < Windows.size(); ++WindowIndex)
        {
            if(!IsWindowFloating(Windows[WindowIndex]->WID, NULL))
            {
                while(!IsLeafNode(Root))
                {
                    if(!IsLeafNode(Root->LeftChild) && IsLeafNode(Root->RightChild))
                        Root = Root->RightChild;
                    else
                        Root = Root->LeftChild;
                }

                DEBUG("CreateTreeFromWindowIDList() Create pair of leafs")
                CreateLeafNodePair(Screen, Root, Root->WindowID, Windows[WindowIndex]->WID, GetOptimalSplitMode(Root));
                Root = RootNode;
            }
        }
    }
    else if(Windows.size() == 1 && !IsWindowFloating(Windows[0]->WID, NULL))
    {
        RootNode->WindowID = Windows[0]->WID;
    }
    else
    {
        free(RootNode);
        RootNode = NULL;
    }

    return RootNode;
}

int GetOptimalSplitMode(tree_node *Node)
{
    return (Node->Container.Width / Node->Container.Height) >= 1.618 ? 1 : 2;
}

void SwapNodeWindowIDs(tree_node *A, tree_node *B)
{
    if(A && B)
    {
        DEBUG("SwapNodeWindowIDs() " << A->WindowID << " with " << B->WindowID)
        int TempWindowID = A->WindowID;
        A->WindowID = B->WindowID;
        B->WindowID = TempWindowID;
        ResizeWindowToContainerSize(A);
        ResizeWindowToContainerSize(B);
    }
}

tree_node *GetNodeFromWindowID(tree_node *Node, int WindowID)
{
    if(Node)
    {
        tree_node *CurrentNode = Node;
        while(CurrentNode->LeftChild)
            CurrentNode = CurrentNode->LeftChild;

        while(CurrentNode)
        {
            if(CurrentNode->WindowID == WindowID)
            {
                DEBUG("GetNodeFromWindowID() " << WindowID)
                return CurrentNode;
            }

            CurrentNode = GetNearestNodeToTheRight(CurrentNode);
        }
    }

    return NULL;
}

void ResizeNodeContainer(screen_info *Screen, tree_node *Node)
{
    if(Node)
    {
        if(Node->LeftChild)
        {
            CreateNodeContainer(Screen, Node->LeftChild, Node->LeftChild->Container.Type);
            ResizeNodeContainer(Screen, Node->LeftChild);
        }

        if(Node->RightChild)
        {
            CreateNodeContainer(Screen, Node->RightChild, Node->RightChild->Container.Type);
            ResizeNodeContainer(Screen, Node->RightChild);
        }
    }
}

tree_node *GetNearestNodeToTheLeft(tree_node *Node)
{
    if(Node)
    {
        if(Node->Parent)
        {
            tree_node *Root = Node->Parent;
            if(Root->LeftChild != Node)
            {
                if(IsLeafNode(Root->LeftChild))
                {
                    return Root->LeftChild;
                }
                else
                {
                    Root = Root->LeftChild;
                    while(!IsLeafNode(Root->RightChild))
                        Root = Root->RightChild;
                }

                return Root->RightChild;
            }
            else
            {
                return GetNearestNodeToTheLeft(Root);
            }
        }
    }

    return NULL;
}

tree_node *GetNearestNodeToTheRight(tree_node *Node)
{
    if(Node)
    {
        if(Node->Parent)
        {
            tree_node *Root = Node->Parent;
            if(Root->RightChild != Node)
            {
                if(IsLeafNode(Root->RightChild))
                {
                    return Root->RightChild;
                }
                else
                {
                    Root = Root->RightChild;
                    while(!IsLeafNode(Root->LeftChild))
                        Root = Root->LeftChild;
                }

                return Root->LeftChild;
            }
            else
            {
                return GetNearestNodeToTheRight(Root);
            }
        }
    }

    return NULL;
}

void CreateNodeContainers(screen_info *Screen, tree_node *Node)
{
    if(Node && Node->LeftChild && Node->RightChild)
    {
        CreateNodeContainerPair(Screen, Node->LeftChild, Node->RightChild, Node->SplitMode);

        CreateNodeContainers(Screen, Node->LeftChild);
        CreateNodeContainers(Screen, Node->RightChild);
    }
}

void ApplyNodeContainer(tree_node *Node)
{
    if(Node)
    {
        if(Node->WindowID != -1)
            ResizeWindowToContainerSize(Node);

        if(Node->LeftChild)
            ApplyNodeContainer(Node->LeftChild);

        if(Node->RightChild)
            ApplyNodeContainer(Node->RightChild);
    }
}

void DestroyNodeTree(tree_node *Node)
{
    if(Node)
    {
        if(Node->LeftChild)
            DestroyNodeTree(Node->LeftChild);

        if(Node->RightChild)
            DestroyNodeTree(Node->RightChild);

        free(Node);
    }
}

void RotateTree(tree_node *Node, int Deg)
{
    if (Node == NULL || IsLeafNode(Node) || Deg == 0)
        return;

    DEBUG("RotateTree() " << Deg << " degrees")

    if((Deg == 90 && Node->SplitMode == 1) ||
       (Deg == 270 && Node->SplitMode == 2) ||
       Deg == 180)
    {
        tree_node *Temp = Node->LeftChild;
        Node->LeftChild = Node->RightChild;
        Node->RightChild = Temp;
    }

    if(Deg != 180)
    {
       if(Node->SplitMode == 2)
           Node->SplitMode = 1;
       else
           Node->SplitMode = 2;
    }

    RotateTree(Node->LeftChild, Deg);
    RotateTree(Node->RightChild, Deg);
}
<commit_msg>removed redundant degree-guard<commit_after>#include "kwm.h"

extern std::vector<window_info> WindowLst;
extern int CurrentSpace;

node_container LeftVerticalContainerSplit(screen_info *Screen, tree_node *Node)
{
    node_container LeftContainer;

    LeftContainer.X = Node->Container.X;
    LeftContainer.Y = Node->Container.Y;
    LeftContainer.Height = Node->Container.Height;

    if(DoesSpaceExistInMapOfScreen(Screen))
        LeftContainer.Width = (Node->Container.Width / 2) - (Screen->Space[CurrentSpace].VerticalGap / 2);
    else
        LeftContainer.Width = (Node->Container.Width / 2) - (Screen->VerticalGap / 2);

    return LeftContainer;
}

node_container RightVerticalContainerSplit(screen_info *Screen, tree_node *Node)
{
    node_container RightContainer;

    RightContainer.Y = Node->Container.Y;
    RightContainer.Height = Node->Container.Height;

    if(DoesSpaceExistInMapOfScreen(Screen))
    {
        RightContainer.X = Node->Container.X + (Node->Container.Width / 2) + (Screen->Space[CurrentSpace].VerticalGap / 2);
        RightContainer.Width = (Node->Container.Width / 2) - (Screen->Space[CurrentSpace].VerticalGap / 2);
    }
    else
    {
        RightContainer.X = Node->Container.X + (Node->Container.Width / 2) + (Screen->VerticalGap / 2);
        RightContainer.Width = (Node->Container.Width / 2) - (Screen->VerticalGap / 2);
    }

    return RightContainer;
}

node_container UpperHorizontalContainerSplit(screen_info *Screen, tree_node *Node)
{
    node_container UpperContainer;

    UpperContainer.X = Node->Container.X;
    UpperContainer.Y = Node->Container.Y;
    UpperContainer.Width = Node->Container.Width;

    if(DoesSpaceExistInMapOfScreen(Screen))
        UpperContainer.Height = (Node->Container.Height / 2) - (Screen->Space[CurrentSpace].HorizontalGap / 2);
    else
        UpperContainer.Height = (Node->Container.Height / 2) - (Screen->HorizontalGap / 2);

    return UpperContainer;
}

node_container LowerHorizontalContainerSplit(screen_info *Screen, tree_node *Node)
{
    node_container LowerContainer;

    LowerContainer.X = Node->Container.X;
    LowerContainer.Width = Node->Container.Width;

    if(DoesSpaceExistInMapOfScreen(Screen))
    {
        LowerContainer.Y = Node->Container.Y + (Node->Container.Height / 2) + (Screen->Space[CurrentSpace].HorizontalGap / 2);
        LowerContainer.Height = (Node->Container.Height / 2) - (Screen->Space[CurrentSpace].HorizontalGap / 2);
    }
    else
    {
        LowerContainer.Y = Node->Container.Y + (Node->Container.Height / 2) + (Screen->HorizontalGap / 2);
        LowerContainer.Height = (Node->Container.Height / 2) - (Screen->HorizontalGap / 2);
    }

    return LowerContainer;
}

void CreateNodeContainer(screen_info *Screen, tree_node *Node, int ContainerType)
{
    switch(ContainerType)
    {
        case 1:
        {
            Node->Container = LeftVerticalContainerSplit(Screen, Node->Parent);
        } break;
        case 2:
        {
            Node->Container = RightVerticalContainerSplit(Screen, Node->Parent);
        } break;
        case 3:
        {
            Node->Container = UpperHorizontalContainerSplit(Screen, Node->Parent);
        } break;
        case 4:
        {
            Node->Container = LowerHorizontalContainerSplit(Screen, Node->Parent);
        } break;
    }

    Node->SplitMode = 0;
    if(ContainerType != -1)
        Node->Container.Type = ContainerType;
}

void CreateNodeContainerPair(screen_info *Screen, tree_node *LeftNode, tree_node *RightNode, int SplitMode)
{
    if(SplitMode == 1)
    {
        CreateNodeContainer(Screen, LeftNode, 1);
        CreateNodeContainer(Screen, RightNode, 2);
    }
    else
    {
        CreateNodeContainer(Screen, LeftNode, 3);
        CreateNodeContainer(Screen, RightNode, 4);
    }
}

tree_node *CreateLeafNode(screen_info *Screen, tree_node *Parent, int WindowID, int ContainerType)
{
    tree_node *Leaf = (tree_node*) malloc(sizeof(tree_node));
    Leaf->Parent = Parent;
    Leaf->WindowID = WindowID;

    CreateNodeContainer(Screen, Leaf, ContainerType);

    Leaf->LeftChild = NULL;
    Leaf->RightChild = NULL;

    return Leaf;
}

tree_node *CreateRootNode()
{
    tree_node *RootNode = (tree_node*) malloc(sizeof(tree_node));
    std::memset(RootNode, '\0', sizeof(tree_node));

    RootNode->WindowID = -1;
    RootNode->Parent = NULL;
    RootNode->LeftChild = NULL;
    RootNode->RightChild = NULL;

    return RootNode;
}

void SetRootNodeContainer(screen_info *Screen, tree_node *Node)
{
    if(DoesSpaceExistInMapOfScreen(Screen))
    {
        Node->Container.X = Screen->X + Screen->Space[CurrentSpace].PaddingLeft;
        Node->Container.Y = Screen->Y + Screen->Space[CurrentSpace].PaddingTop;
        Node->Container.Width = Screen->Width - Screen->Space[CurrentSpace].PaddingLeft - Screen->Space[CurrentSpace].PaddingRight;
        Node->Container.Height = Screen->Height - Screen->Space[CurrentSpace].PaddingTop - Screen->Space[CurrentSpace].PaddingBottom;
    }
    else
    {
        Node->Container.X = Screen->X + Screen->PaddingLeft;
        Node->Container.Y = Screen->Y + Screen->PaddingTop;
        Node->Container.Width = Screen->Width - Screen->PaddingLeft - Screen->PaddingRight;
        Node->Container.Height = Screen->Height - Screen->PaddingTop - Screen->PaddingBottom;
    }

    Node->Container.Type = 0;
    Node->SplitMode = 0;
}

void CreateLeafNodePair(screen_info *Screen, tree_node *Parent, int LeftWindowID, int RightWindowID, int SplitMode)
{
    Parent->WindowID = -1;
    Parent->SplitMode = SplitMode;

    if(SplitMode == 1)
    {
        Parent->LeftChild = CreateLeafNode(Screen, Parent, LeftWindowID, 1);
        Parent->RightChild = CreateLeafNode(Screen, Parent, RightWindowID, 2);
    }
    else
    {
        Parent->LeftChild = CreateLeafNode(Screen, Parent, LeftWindowID, 3);
        Parent->RightChild = CreateLeafNode(Screen, Parent, RightWindowID, 4);
    }
}

bool IsLeafNode(tree_node *Node)
{
    return Node->LeftChild == NULL && Node->RightChild == NULL ? true : false;
}

tree_node *CreateTreeFromWindowIDList(screen_info *Screen, std::vector<window_info*> *WindowsPtr)
{
    std::vector<window_info*> &Windows = *WindowsPtr;
    tree_node *RootNode = CreateRootNode();
    SetRootNodeContainer(Screen, RootNode);

    if(Windows.size() > 1)
    {
        tree_node *Root = RootNode;
        int FirstIndex;
        bool FoundValidWindow = false;
        for(FirstIndex = 0; FirstIndex < Windows.size(); ++FirstIndex)
        {
            if(!IsWindowFloating(Windows[FirstIndex]->WID, NULL))
            {
                Root->WindowID = Windows[FirstIndex]->WID;
                FoundValidWindow = true;
                break;
            }
        }

        if(!FoundValidWindow)
        {
            free(RootNode);
            return NULL;
        }

        for(int WindowIndex = FirstIndex + 1; WindowIndex < Windows.size(); ++WindowIndex)
        {
            if(!IsWindowFloating(Windows[WindowIndex]->WID, NULL))
            {
                while(!IsLeafNode(Root))
                {
                    if(!IsLeafNode(Root->LeftChild) && IsLeafNode(Root->RightChild))
                        Root = Root->RightChild;
                    else
                        Root = Root->LeftChild;
                }

                DEBUG("CreateTreeFromWindowIDList() Create pair of leafs")
                CreateLeafNodePair(Screen, Root, Root->WindowID, Windows[WindowIndex]->WID, GetOptimalSplitMode(Root));
                Root = RootNode;
            }
        }
    }
    else if(Windows.size() == 1 && !IsWindowFloating(Windows[0]->WID, NULL))
    {
        RootNode->WindowID = Windows[0]->WID;
    }
    else
    {
        free(RootNode);
        RootNode = NULL;
    }

    return RootNode;
}

int GetOptimalSplitMode(tree_node *Node)
{
    return (Node->Container.Width / Node->Container.Height) >= 1.618 ? 1 : 2;
}

void SwapNodeWindowIDs(tree_node *A, tree_node *B)
{
    if(A && B)
    {
        DEBUG("SwapNodeWindowIDs() " << A->WindowID << " with " << B->WindowID)
        int TempWindowID = A->WindowID;
        A->WindowID = B->WindowID;
        B->WindowID = TempWindowID;
        ResizeWindowToContainerSize(A);
        ResizeWindowToContainerSize(B);
    }
}

tree_node *GetNodeFromWindowID(tree_node *Node, int WindowID)
{
    if(Node)
    {
        tree_node *CurrentNode = Node;
        while(CurrentNode->LeftChild)
            CurrentNode = CurrentNode->LeftChild;

        while(CurrentNode)
        {
            if(CurrentNode->WindowID == WindowID)
            {
                DEBUG("GetNodeFromWindowID() " << WindowID)
                return CurrentNode;
            }

            CurrentNode = GetNearestNodeToTheRight(CurrentNode);
        }
    }

    return NULL;
}

void ResizeNodeContainer(screen_info *Screen, tree_node *Node)
{
    if(Node)
    {
        if(Node->LeftChild)
        {
            CreateNodeContainer(Screen, Node->LeftChild, Node->LeftChild->Container.Type);
            ResizeNodeContainer(Screen, Node->LeftChild);
        }

        if(Node->RightChild)
        {
            CreateNodeContainer(Screen, Node->RightChild, Node->RightChild->Container.Type);
            ResizeNodeContainer(Screen, Node->RightChild);
        }
    }
}

tree_node *GetNearestNodeToTheLeft(tree_node *Node)
{
    if(Node)
    {
        if(Node->Parent)
        {
            tree_node *Root = Node->Parent;
            if(Root->LeftChild != Node)
            {
                if(IsLeafNode(Root->LeftChild))
                {
                    return Root->LeftChild;
                }
                else
                {
                    Root = Root->LeftChild;
                    while(!IsLeafNode(Root->RightChild))
                        Root = Root->RightChild;
                }

                return Root->RightChild;
            }
            else
            {
                return GetNearestNodeToTheLeft(Root);
            }
        }
    }

    return NULL;
}

tree_node *GetNearestNodeToTheRight(tree_node *Node)
{
    if(Node)
    {
        if(Node->Parent)
        {
            tree_node *Root = Node->Parent;
            if(Root->RightChild != Node)
            {
                if(IsLeafNode(Root->RightChild))
                {
                    return Root->RightChild;
                }
                else
                {
                    Root = Root->RightChild;
                    while(!IsLeafNode(Root->LeftChild))
                        Root = Root->LeftChild;
                }

                return Root->LeftChild;
            }
            else
            {
                return GetNearestNodeToTheRight(Root);
            }
        }
    }

    return NULL;
}

void CreateNodeContainers(screen_info *Screen, tree_node *Node)
{
    if(Node && Node->LeftChild && Node->RightChild)
    {
        CreateNodeContainerPair(Screen, Node->LeftChild, Node->RightChild, Node->SplitMode);

        CreateNodeContainers(Screen, Node->LeftChild);
        CreateNodeContainers(Screen, Node->RightChild);
    }
}

void ApplyNodeContainer(tree_node *Node)
{
    if(Node)
    {
        if(Node->WindowID != -1)
            ResizeWindowToContainerSize(Node);

        if(Node->LeftChild)
            ApplyNodeContainer(Node->LeftChild);

        if(Node->RightChild)
            ApplyNodeContainer(Node->RightChild);
    }
}

void DestroyNodeTree(tree_node *Node)
{
    if(Node)
    {
        if(Node->LeftChild)
            DestroyNodeTree(Node->LeftChild);

        if(Node->RightChild)
            DestroyNodeTree(Node->RightChild);

        free(Node);
    }
}

void RotateTree(tree_node *Node, int Deg)
{
    if (Node == NULL || IsLeafNode(Node))
        return;

    DEBUG("RotateTree() " << Deg << " degrees")

    if((Deg == 90 && Node->SplitMode == 1) ||
       (Deg == 270 && Node->SplitMode == 2) ||
       Deg == 180)
    {
        tree_node *Temp = Node->LeftChild;
        Node->LeftChild = Node->RightChild;
        Node->RightChild = Temp;
    }

    if(Deg != 180)
    {
       if(Node->SplitMode == 2)
           Node->SplitMode = 1;
       else
           Node->SplitMode = 2;
    }

    RotateTree(Node->LeftChild, Deg);
    RotateTree(Node->RightChild, Deg);
}
<|endoftext|>