{
  _displaycontrol &= ~LCD_DISPLAYON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}

#include "LiquidCrystalRus.h"

#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <avr/pgmspace.h>

#if defined(ARDUINO) && ARDUINO >= 100
  #include "Arduino.h"
#else
  #include "WProgram.h"
#endif

// it is a russian alphabet translation
const PROGMEM uint8_t utf_recode[] =
       { 0x41,0xa0,0x42,0xa1,0xe0,0x45,0xa3,0xa4,0xa5,0xa6,0x4b,0xa7,0x4d,0x48,0x4f,
         0xa8,0x50,0x43,0x54,0xa9,0xaa,0x58,0xe1,0xab,0xac,0xe2,0xad,0xae,0x62,0xaf,0xb0,0xb1,
         0x61,0xb2,0xb3,0xb4,0xe3,0x65,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0x6f,
         0xbe,0x70,0x63,0xbf,0x79,0xe4,0x78,0xe5,0xc0,0xc1,0xe6,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7
        };

// When the display powers up, it is configured as follows:
// 4. Entry mode set:
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
// can't assume that it's in that state when a sketch starts (and the
// LiquidCrystal constructor is called).
// by Ilya V. Danilov http://example.com

LiquidCrystalRus::LiquidCrystalRus(uint8_t rs, uint8_t rw, uint8_t enable,
			     uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
			     uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
  init(0, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
}

LiquidCrystalRus::LiquidCrystalRus(uint8_t rs, uint8_t enable,
			     uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
			     uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
  init(0, rs, 255, enable, d0, d1, d2, d3, d4, d5, d6, d7);
}

LiquidCrystalRus::LiquidCrystalRus(uint8_t rs, uint8_t rw, uint8_t enable,
			     uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
{
  init(1, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0);
}

LiquidCrystalRus::LiquidCrystalRus(uint8_t rs,  uint8_t enable,
			     uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
{
  init(1, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0);
}

void LiquidCrystalRus::init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
			 uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
			 uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
  _rs_pin = rs;
  _rw_pin = rw;
  _enable_pin = enable;

  _data_pins[0] = d0;
  _data_pins[1] = d1;
  _data_pins[2] = d2;
  _data_pins[3] = d3;
  _data_pins[4] = d4;
  _data_pins[5] = d5;
  _data_pins[6] = d6;
  _data_pins[7] = d7;

  pinMode(_rs_pin, OUTPUT);
  // we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
  if (_rw_pin != 255) {
    pinMode(_rw_pin, OUTPUT);
  }
  pinMode(_enable_pin, OUTPUT);

  if (fourbitmode)
    _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
  else
    _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;

  begin(16, 1);
}

void LiquidCrystalRus::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
  if (lines > 1) {
    _displayfunction |= LCD_2LINE;
  }
  _numlines = lines;
  _currline = 0;

  // for some 1 line displays you can select a 10 pixel high font
  if ((dotsize != 0) && (lines == 1)) {
    _displayfunction |= LCD_5x10DOTS;
  }

  // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
  // according to datasheet, we need at least 40ms after power rises above 2.7V
  // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
  delayMicroseconds(50000);
  // Now we pull both RS and R/W low to begin commands
  digitalWrite(_rs_pin, LOW);
  digitalWrite(_enable_pin, LOW);
  if (_rw_pin != 255) {
    digitalWrite(_rw_pin, LOW);
  }

  //put the LCD into 4 bit or 8 bit mode
  if (! (_displayfunction & LCD_8BITMODE)) {
    // this is according to the hitachi HD44780 datasheet

    // we start in 8bit mode, try to set 4 bit mode
    writeNbits(0x03,4);
    delayMicroseconds(4500); // wait min 4.1ms

    writeNbits(0x03,4);
    delayMicroseconds(4500); // wait min 4.1ms

    // third go!
    writeNbits(0x03,4);
    delayMicroseconds(150);

    writeNbits(0x02,4);
  } else {
    // this is according to the hitachi HD44780 datasheet

    // Send function set command sequence
    command(LCD_FUNCTIONSET | _displayfunction);
    delayMicroseconds(4500);  // wait more than 4.1ms

    command(LCD_FUNCTIONSET | _displayfunction);
    delayMicroseconds(150);

    // third go
    command(LCD_FUNCTIONSET | _displayfunction);
  }

  command(LCD_FUNCTIONSET | _displayfunction);

  // turn the display on with no cursor or blinking default
  _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
  display();

  // clear it off
  clear();

  // Initialize to default text direction (for romance languages)
  _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
  // set the entry mode
  command(LCD_ENTRYMODESET | _displaymode);

}

void LiquidCrystalRus::setDRAMModel(uint8_t model) {
  _dram_model = model;
}

/********** high level commands, for the user! */
void LiquidCrystalRus::clear()
{
  command(LCD_CLEARDISPLAY);  // clear display, set cursor position to zero
  delayMicroseconds(2000);  // this command takes a long time!
}

void LiquidCrystalRus::home()
{
  command(LCD_RETURNHOME);  // set cursor position to zero
  delayMicroseconds(2000);  // this command takes a long time!
}

void LiquidCrystalRus::setCursor(uint8_t col, uint8_t row)
{
  int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
  if ( row >= _numlines ) {
    row = _numlines-1;    // we count rows starting w/0
  }

  command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
}

// Turn the display on/off (quickly)
void LiquidCrystalRus::noDisplay()

void LiquidCrystalRus::display() {
  _displaycontrol |= LCD_DISPLAYON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// Turns the underline cursor on/off
void LiquidCrystalRus::noCursor() {
  _displaycontrol &= ~LCD_CURSORON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystalRus::cursor() {
  _displaycontrol |= LCD_CURSORON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// Turn on and off the blinking cursor
void LiquidCrystalRus::noBlink() {
  _displaycontrol &= ~LCD_BLINKON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystalRus::blink() {
  _displaycontrol |= LCD_BLINKON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// These commands scroll the display without changing the RAM
void LiquidCrystalRus::scrollDisplayLeft(void) {
  command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
}
void LiquidCrystalRus::scrollDisplayRight(void) {
  command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
}

// This is for text that flows Left to Right
void LiquidCrystalRus::leftToRight(void) {
  _displaymode |= LCD_ENTRYLEFT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// This is for text that flows Right to Left
void LiquidCrystalRus::rightToLeft(void) {
  _displaymode &= ~LCD_ENTRYLEFT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// This will 'right justify' text from the cursor
void LiquidCrystalRus::autoscroll(void) {
  _displaymode |= LCD_ENTRYSHIFTINCREMENT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// This will 'left justify' text from the cursor
void LiquidCrystalRus::noAutoscroll(void) {
  _displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// Allows us to fill the first 8 CGRAM locations
// with custom characters
void LiquidCrystalRus::createChar(uint8_t location, uint8_t charmap[]) {
  location &= 0x7; // we only have 8 locations 0-7
  command(LCD_SETCGRAMADDR | (location << 3));
  for (int i=0; i<8; i++) {
    write(charmap[i]);
  }
}

/*********** mid level commands, for sending data/cmds */

inline void LiquidCrystalRus::command(uint8_t value) {
  send(value, LOW);
}

#if defined(ARDUINO) && ARDUINO >= 100
  size_t LiquidCrystalRus::write(uint8_t value)
#else
  void   LiquidCrystalRus::write(uint8_t value)
#endif
{
  uint8_t out_char=value;

  if (_dram_model == LCD_DRAM_WH1601) {
    uint8_t ac=recv(LOW) & 0x7f;
    if (ac>7 && ac<0x14) command(LCD_SETDDRAMADDR | (0x40+ac-8));
  }

  if (value>=0x80) { // UTF-8 handling
    if (value >= 0xc0) {
      utf_hi_char = value - 0xd0;
    } else {
      value &= 0x3f;
      if (!utf_hi_char && (value == 1))
        send(0xa2,HIGH); // ╗
      else if ((utf_hi_char == 1) && (value == 0x11))
        send(0xb5,HIGH); // ╦
      else
        send(pgm_read_byte_near(utf_recode + value + (utf_hi_char<<6) - 0x10), HIGH);
    }
  } else send(out_char, HIGH);
#if defined(ARDUINO) && ARDUINO >= 100
  return 1; // assume sucess
#endif
}

/************ low level data pushing commands **********/

// write either command or data, with automatic 4/8-bit selection
void LiquidCrystalRus::send(uint8_t value, uint8_t mode) {
  digitalWrite(_rs_pin, mode);

  // if there is a RW pin indicated, set it low to Write
  if (_rw_pin != 255) {
    digitalWrite(_rw_pin, LOW);
  }

  if (_displayfunction & LCD_8BITMODE) {
    writeNbits(value,8);
  } else {
    writeNbits(value>>4,4);
    writeNbits(value,4);
  }
}

// read  data, with automatic 4/8-bit selection
uint8_t LiquidCrystalRus::recv(uint8_t mode) {
  uint8_t retval;
  digitalWrite(_rs_pin, mode);

  // if there is a RW pin indicated, set it low to Write
  if (_rw_pin != 255) {
    digitalWrite(_rw_pin, HIGH);
  }

  if (_displayfunction & LCD_8BITMODE) {
    retval = readNbits(8);
  } else {
    retval = readNbits(4) << 4;
    retval |= readNbits(4);
  }
  return retval;
}
void LiquidCrystalRus::pulseEnable() {
  digitalWrite(_enable_pin, LOW);
  delayMicroseconds(1);
  digitalWrite(_enable_pin, HIGH);
  delayMicroseconds(1);    // enable pulse must be >450ns
  digitalWrite(_enable_pin, LOW);
  delayMicroseconds(100);   // commands need > 37us to settle
}

void LiquidCrystalRus::writeNbits(uint8_t value, uint8_t n) {
  for (int i = 0; i < n; i++) {
    pinMode(_data_pins[i], OUTPUT);
    digitalWrite(_data_pins[i], (value >> i) & 0x01);
  }

  pulseEnable();
}

uint8_t LiquidCrystalRus::readNbits(uint8_t n) {
  uint8_t retval=0;
  for (int i = 0; i < n; i++) {
    pinMode(_data_pins[i], INPUT);
  }

  digitalWrite(_enable_pin, LOW);
  delayMicroseconds(1);
  digitalWrite(_enable_pin, HIGH);
  delayMicroseconds(1);    // enable pulse must be >450ns

  for (int i = 0; i < n; i++) {
    retval |= (digitalRead(_data_pins[i]) == HIGH)?(1 << i):0;
  }

  digitalWrite(_enable_pin, LOW);

  return retval;
}


#include "LiquidCrystalRus.h"

#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <avr/pgmspace.h>

#if defined(ARDUINO) && ARDUINO >= 100
  #include "Arduino.h"
#else
  #include "WProgram.h"
#endif

// it is a russian alphabet translation
const PROGMEM uint8_t utf_recode[] =
       { 0x41,0xa0,0x42,0xa1,0xe0,0x45,0xa3,0xa4,0xa5,0xa6,0x4b,0xa7,0x4d,0x48,0x4f,
         0xa8,0x50,0x43,0x54,0xa9,0xaa,0x58,0xe1,0xab,0xac,0xe2,0xad,0xae,0x62,0xaf,0xb0,0xb1,
         0x61,0xb2,0xb3,0xb4,0xe3,0x65,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0x6f,
         0xbe,0x70,0x63,0xbf,0x79,0xe4,0x78,0xe5,0xc0,0xc1,0xe6,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7
        };

// When the display powers up, it is configured as follows:
// 4. Entry mode set:
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
// can't assume that it's in that state when a sketch starts (and the
// LiquidCrystal constructor is called).
// by Ilya V. Danilov http://example.com

LiquidCrystalRus::LiquidCrystalRus(uint8_t rs, uint8_t rw, uint8_t enable,
			     uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
			     uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
  init(0, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
}

LiquidCrystalRus::LiquidCrystalRus(uint8_t rs, uint8_t enable,
			     uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
			     uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
  init(0, rs, 255, enable, d0, d1, d2, d3, d4, d5, d6, d7);
}

LiquidCrystalRus::LiquidCrystalRus(uint8_t rs, uint8_t rw, uint8_t enable,
			     uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
{
  init(1, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0);
}

LiquidCrystalRus::LiquidCrystalRus(uint8_t rs,  uint8_t enable,
			     uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
{
  init(1, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0);
}

void LiquidCrystalRus::init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
			 uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
			 uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
  _rs_pin = rs;
  _rw_pin = rw;
  _enable_pin = enable;

  _data_pins[0] = d0;
  _data_pins[1] = d1;
  _data_pins[2] = d2;
  _data_pins[3] = d3;
  _data_pins[4] = d4;
  _data_pins[5] = d5;
  _data_pins[6] = d6;
  _data_pins[7] = d7;

  pinMode(_rs_pin, OUTPUT);
  // we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
  if (_rw_pin != 255) {
    pinMode(_rw_pin, OUTPUT);
  }
  pinMode(_enable_pin, OUTPUT);

  if (fourbitmode)
    _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
  else
    _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;

  begin(16, 1);
}

void LiquidCrystalRus::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
  if (lines > 1) {
    _displayfunction |= LCD_2LINE;
  }
  _numlines = lines;
  _currline = 0;

  // for some 1 line displays you can select a 10 pixel high font
  if ((dotsize != 0) && (lines == 1)) {
    _displayfunction |= LCD_5x10DOTS;
  }

  // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
  // according to datasheet, we need at least 40ms after power rises above 2.7V
  // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
  delayMicroseconds(50000);
  // Now we pull both RS and R/W low to begin commands
  digitalWrite(_rs_pin, LOW);
  digitalWrite(_enable_pin, LOW);
  if (_rw_pin != 255) {
    digitalWrite(_rw_pin, LOW);
  }

  //put the LCD into 4 bit or 8 bit mode
  if (! (_displayfunction & LCD_8BITMODE)) {
    // this is according to the hitachi HD44780 datasheet

    // we start in 8bit mode, try to set 4 bit mode
    writeNbits(0x03,4);
    delayMicroseconds(4500); // wait min 4.1ms

    writeNbits(0x03,4);
    delayMicroseconds(4500); // wait min 4.1ms

    // third go!
    writeNbits(0x03,4);
    delayMicroseconds(150);

    writeNbits(0x02,4);
  } else {
    // this is according to the hitachi HD44780 datasheet

    // Send function set command sequence
    command(LCD_FUNCTIONSET | _displayfunction);
    delayMicroseconds(4500);  // wait more than 4.1ms

    command(LCD_FUNCTIONSET | _displayfunction);
    delayMicroseconds(150);

    // third go
    command(LCD_FUNCTIONSET | _displayfunction);
  }

  command(LCD_FUNCTIONSET | _displayfunction);

  // turn the display on with no cursor or blinking default
  _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
  display();

  // clear it off
  clear();

  // Initialize to default text direction (for romance languages)
  _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
  // set the entry mode
  command(LCD_ENTRYMODESET | _displaymode);

}

void LiquidCrystalRus::setDRAMModel(uint8_t model) {
  _dram_model = model;
}

/********** high level commands, for the user! */
void LiquidCrystalRus::clear()
{
  command(LCD_CLEARDISPLAY);  // clear display, set cursor position to zero
  delayMicroseconds(2000);  // this command takes a long time!
}

void LiquidCrystalRus::home()
{
  c

  // set cursor position to zero
  delayMicroseconds(2000);  // this command takes a long time!
}

void LiquidCrystalRus::setCursor(uint8_t col, uint8_t row)
{
  int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
  if ( row >= _numlines ) {
    row = _numlines-1;    // we count rows starting w/0
  }

  command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
}

// Turn the display on/off (quickly)
void LiquidCrystalRus::noDisplay() {
  _displaycontrol &= ~LCD_DISPLAYON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystalRus::display() {
  _displaycontrol |= LCD_DISPLAYON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// Turns the underline cursor on/off
void LiquidCrystalRus::noCursor() {
  _displaycontrol &= ~LCD_CURSORON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystalRus::cursor() {
  _displaycontrol |= LCD_CURSORON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// Turn on and off the blinking cursor
void LiquidCrystalRus::noBlink() {
  _displaycontrol &= ~LCD_BLINKON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystalRus::blink() {
  _displaycontrol |= LCD_BLINKON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// These commands scroll the display without changing the RAM
void LiquidCrystalRus::scrollDisplayLeft(void) {
  command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
}
void LiquidCrystalRus::scrollDisplayRight(void) {
  command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
}

// This is for text that flows Left to Right
void LiquidCrystalRus::leftToRight(void) {
  _displaymode |= LCD_ENTRYLEFT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// This is for text that flows Right to Left
void LiquidCrystalRus::rightToLeft(void) {
  _displaymode &= ~LCD_ENTRYLEFT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// This will 'right justify' text from the cursor
void LiquidCrystalRus::autoscroll(void) {
  _displaymode |= LCD_ENTRYSHIFTINCREMENT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// This will 'left justify' text from the cursor
void LiquidCrystalRus::noAutoscroll(void) {
  _displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// Allows us to fill the first 8 CGRAM locations
// with custom characters
void LiquidCrystalRus::createChar(uint8_t location, uint8_t charmap[]) {
  location &= 0x7; // we only have 8 locations 0-7
  command(LCD_SETCGRAMADDR | (location << 3));
  for (int i=0; i<8; i++) {
    write(charmap[i]);
  }
}

/*********** mid level commands, for sending data/cmds */

inline void LiquidCrystalRus::command(uint8_t value) {
  send(value, LOW);
}

#if defined(ARDUINO) && ARDUINO >= 100
  size_t LiquidCrystalRus::write(uint8_t value)
#else
  void   LiquidCrystalRus::write(uint8_t value)
#endif
{
  uint8_t out_char=value;

  if (_dram_model == LCD_DRAM_WH1601) {
    uint8_t ac=recv(LOW) & 0x7f;
    if (ac>7 && ac<0x14) command(LCD_SETDDRAMADDR | (0x40+ac-8));
  }

  if (value>=0x80) { // UTF-8 handling
    if (value >= 0xc0) {
      utf_hi_char = value - 0xd0;
    } else {
      value &= 0x3f;
      if (!utf_hi_char && (value == 1))
        send(0xa2,HIGH); // ╗
      else if ((utf_hi_char == 1) && (value == 0x11))
        send(0xb5,HIGH); // ╦
      else
        send(pgm_read_byte_near(utf_recode + value + (utf_hi_char<<6) - 0x10), HIGH);
    }
  } else send(out_char, HIGH);
#if defined(ARDUINO) && ARDUINO >= 100
  return 1; // assume sucess
#endif
}

/************ low level data pushing commands **********/

// write either command or data, with automatic 4/8-bit selection
void LiquidCrystalRus::send(uint8_t value, uint8_t mode) {
  digitalWrite(_rs_pin, mode);

  // if there is a RW pin indicated, set it low to Write
  if (_rw_pin != 255) {
    digitalWrite(_rw_pin, LOW);
  }

  if (_displayfunction & LCD_8BITMODE) {
    writeNbits(value,8);
  } else {
    writeNbits(value>>4,4);
    writeNbits(value,4);
  }
}

// read  data, with automatic 4/8-bit selection
uint8_t LiquidCrystalRus::recv(uint8_t mode) {
  uint8_t retval;
  digitalWrite(_rs_pin, mode);

  // if there is a RW pin indicated, set it low to Write
  if (_rw_pin != 255) {
    digitalWrite(_rw_pin, HIGH);
  }

  if (_displayfunction & LCD_8BITMODE) {
    retval = readNbits(8);
  } else {
    retval = readNbits(4) << 4;
    retval |= readNbits(4);
  }
  return retval;
}
void LiquidCrystalRus::pulseEnable() {
  digitalWrite(_enable_pin, LOW);
  delayMicroseconds(1);
  digitalWrite(_enable_pin, HIGH);
  delayMicroseconds(1);    // enable pulse must be >450ns
  digitalWrite(_enable_pin, LOW);
  delayMicroseconds(100);   // commands need > 37us to settle
}

void LiquidCrystalRus::writeNbits(uint8_t value, uint8_t n) {
  for (int i = 0; i < n; i++) {
    pinMode(_data_pins[i], OUTPUT);
    digitalWrite(_data_pins[i], (value >> i) & 0x01);
  }

  pulseEnable();
}

uint8_t LiquidCrystalRus::readNbits(uint8_t n) {
  uint8_t retval=0;
  for (int i = 0; i < n; i++) {
    pinMode(_data_pins[i], INPUT);
  }

  digitalWrite(_enable_pin, LOW);
  delayMicroseconds(1);
  digitalWrite(_enable_pin, HIGH);
  delayMicroseconds(1);    // enable pulse must be >450ns

  for (int i = 0; i < n; i++) {
    retval |= (digitalRead(_data_pins[i]) == HIGH)?(1 << i):0;
  }

  digitalWrite(_enable_pin, LOW);

  return retval;
}


void LiquidCrystalRus::scrollDisplayLeft(void) {
  command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
}

#include "LiquidCrystalRus.h"

#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <avr/pgmspace.h>

#if defined(ARDUINO) && ARDUINO >= 100
  #include "Arduino.h"
#else
  #include "WProgram.h"
#endif

// it is a russian alphabet translation
const PROGMEM uint8_t utf_recode[] =
       { 0x41,0xa0,0x42,0xa1,0xe0,0x45,0xa3,0xa4,0xa5,0xa6,0x4b,0xa7,0x4d,0x48,0x4f,
         0xa8,0x50,0x43,0x54,0xa9,0xaa,0x58,0xe1,0xab,0xac,0xe2,0xad,0xae,0x62,0xaf,0xb0,0xb1,
         0x61,0xb2,0xb3,0xb4,0xe3,0x65,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0x6f,
         0xbe,0x70,0x63,0xbf,0x79,0xe4,0x78,0xe5,0xc0,0xc1,0xe6,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7
        };

// When the display powers up, it is configured as follows:
// 4. Entry mode set:
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
// can't assume that it's in that state when a sketch starts (and the
// LiquidCrystal constructor is called).
// by Ilya V. Danilov http://example.com

LiquidCrystalRus::LiquidCrystalRus(uint8_t rs, uint8_t rw, uint8_t enable,
			     uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
			     uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
  init(0, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
}

LiquidCrystalRus::LiquidCrystalRus(uint8_t rs, uint8_t enable,
			     uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
			     uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
  init(0, rs, 255, enable, d0, d1, d2, d3, d4, d5, d6, d7);
}

LiquidCrystalRus::LiquidCrystalRus(uint8_t rs, uint8_t rw, uint8_t enable,
			     uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
{
  init(1, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0);
}

LiquidCrystalRus::LiquidCrystalRus(uint8_t rs,  uint8_t enable,
			     uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
{
  init(1, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0);
}

void LiquidCrystalRus::init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
			 uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
			 uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
  _rs_pin = rs;
  _rw_pin = rw;
  _enable_pin = enable;

  _data_pins[0] = d0;
  _data_pins[1] = d1;
  _data_pins[2] = d2;
  _data_pins[3] = d3;
  _data_pins[4] = d4;
  _data_pins[5] = d5;
  _data_pins[6] = d6;
  _data_pins[7] = d7;

  pinMode(_rs_pin, OUTPUT);
  // we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
  if (_rw_pin != 255) {
    pinMode(_rw_pin, OUTPUT);
  }
  pinMode(_enable_pin, OUTPUT);

  if (fourbitmode)
    _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
  else
    _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;

  begin(16, 1);
}

void LiquidCrystalRus::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
  if (lines > 1) {
    _displayfunction |= LCD_2LINE;
  }
  _numlines = lines;
  _currline = 0;

  // for some 1 line displays you can select a 10 pixel high font
  if ((dotsize != 0) && (lines == 1)) {
    _displayfunction |= LCD_5x10DOTS;
  }

  // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
  // according to datasheet, we need at least 40ms after power rises above 2.7V
  // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
  delayMicroseconds(50000);
  // Now we pull both RS and R/W low to begin commands
  digitalWrite(_rs_pin, LOW);
  digitalWrite(_enable_pin, LOW);
  if (_rw_pin != 255) {
    digitalWrite(_rw_pin, LOW);
  }

  //put the LCD into 4 bit or 8 bit mode
  if (! (_displayfunction & LCD_8BITMODE)) {
    // this is according to the hitachi HD44780 datasheet

    // we start in 8bit mode, try to set 4 bit mode
    writeNbits(0x03,4);
    delayMicroseconds(4500); // wait min 4.1ms

    writeNbits(0x03,4);
    delayMicroseconds(4500); // wait min 4.1ms

    // third go!
    writeNbits(0x03,4);
    delayMicroseconds(150);

    writeNbits(0x02,4);
  } else {
    // this is according to the hitachi HD44780 datasheet

    // Send function set command sequence
    command(LCD_FUNCTIONSET | _displayfunction);
    delayMicroseconds(4500);  // wait more than 4.1ms

    command(LCD_FUNCTIONSET | _displayfunction);
    delayMicroseconds(150);

    // third go
    command(LCD_FUNCTIONSET | _displayfunction);
  }

  command(LCD_FUNCTIONSET | _displayfunction);

  // turn the display on with no cursor or blinking default
  _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
  display();

  // clear it off
  clear();

  // Initialize to default text direction (for romance languages)
  _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
  // set the entry mode
  command(LCD_ENTRYMODESET | _displaymode);

}

void LiquidCrystalRus::setDRAMModel(uint8_t model) {
  _dram_model = model;
}

/********** high level commands, for the user! */
void LiquidCrystalRus::clear()
{
  command(LCD_CLEARDISPLAY);  // clear display, set cursor position to zero
  delayMicroseconds(2000);  // this command takes a long time!
}

void LiquidCrystalRus::home()
{
  command(LCD_RETURNHOME);  // set cursor position to zero
  delayMicroseconds(2000);  // this command takes a long time!
}

void LiquidCrystalRus::setCursor(uint8_t col, uint8_t row)
{
  int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
  if ( row >= _numlines ) {
    row = _numlines-1;    // we count rows starting w/0
  }

  command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
}

// Turn the display on/off (quickly)
void LiquidCrystalRus::noDisplay() {
  _displaycontrol &= ~LCD_DISPLAYON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystalRus::display() {
  _displaycontrol |= LCD_DISPLAYON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// Turns the underline cursor on/off
void LiquidCrystalRus::noCursor() {
  _displaycontrol &= ~LCD_CURSORON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystalRus::cursor() {
  _displaycontrol |= LCD_CURSORON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// Turn on and off the blinking cursor
void LiquidCrystalRus::noBlink() {
  _displaycontrol &= ~LCD_BLINKON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystalRus::blink() {
  _displaycontrol |= LCD_BLINKON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// These commands scroll the display without changing the RAM

void LiquidCrystalRus::scrollDisplayRight(void) {
  command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
}

// This is for text that flows Left to Right
void LiquidCrystalRus::leftToRight(void) {
  _displaymode |= LCD_ENTRYLEFT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// This is for text that flows Right to Left
void LiquidCrystalRus::rightToLeft(void) {
  _displaymode &= ~LCD_ENTRYLEFT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// This will 'right justify' text from the cursor
void LiquidCrystalRus::autoscroll(void) {
  _displaymode |= LCD_ENTRYSHIFTINCREMENT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// This will 'left justify' text from the cursor
void LiquidCrystalRus::noAutoscroll(void) {
  _displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// Allows us to fill the first 8 CGRAM locations
// with custom characters
void LiquidCrystalRus::createChar(uint8_t location, uint8_t charmap[]) {
  location &= 0x7; // we only have 8 locations 0-7
  command(LCD_SETCGRAMADDR | (location << 3));
  for (int i=0; i<8; i++) {
    write(charmap[i]);
  }
}

/*********** mid level commands, for sending data/cmds */

inline void LiquidCrystalRus::command(uint8_t value) {
  send(value, LOW);
}

#if defined(ARDUINO) && ARDUINO >= 100
  size_t LiquidCrystalRus::write(uint8_t value)
#else
  void   LiquidCrystalRus::write(uint8_t value)
#endif
{
  uint8_t out_char=value;

  if (_dram_model == LCD_DRAM_WH1601) {
    uint8_t ac=recv(LOW) & 0x7f;
    if (ac>7 && ac<0x14) command(LCD_SETDDRAMADDR | (0x40+ac-8));
  }

  if (value>=0x80) { // UTF-8 handling
    if (value >= 0xc0) {
      utf_hi_char = value - 0xd0;
    } else {
      value &= 0x3f;
      if (!utf_hi_char && (value == 1))
        send(0xa2,HIGH); // ╗
      else if ((utf_hi_char == 1) && (value == 0x11))
        send(0xb5,HIGH); // ╦
      else
        send(pgm_read_byte_near(utf_recode + value + (utf_hi_char<<6) - 0x10), HIGH);
    }
  } else send(out_char, HIGH);
#if defined(ARDUINO) && ARDUINO >= 100
  return 1; // assume sucess
#endif
}

/************ low level data pushing commands **********/

// write either command or data, with automatic 4/8-bit selection
void LiquidCrystalRus::send(uint8_t value, uint8_t mode) {
  digitalWrite(_rs_pin, mode);

  // if there is a RW pin indicated, set it low to Write
  if (_rw_pin != 255) {
    digitalWrite(_rw_pin, LOW);
  }

  if (_displayfunction & LCD_8BITMODE) {
    writeNbits(value,8);
  } else {
    writeNbits(value>>4,4);
    writeNbits(value,4);
  }
}

// read  data, with automatic 4/8-bit selection
uint8_t LiquidCrystalRus::recv(uint8_t mode) {
  uint8_t retval;
  digitalWrite(_rs_pin, mode);

  // if there is a RW pin indicated, set it low to Write
  if (_rw_pin != 255) {
    digitalWrite(_rw_pin, HIGH);
  }

  if (_displayfunction & LCD_8BITMODE) {
    retval = readNbits(8);
  } else {
    retval = readNbits(4) << 4;
    retval |= readNbits(4);
  }
  return retval;
}
void LiquidCrystalRus::pulseEnable() {
  digitalWrite(_enable_pin, LOW);
  delayMicroseconds(1);
  digitalWrite(_enable_pin, HIGH);
  delayMicroseconds(1);    // enable pulse must be >450ns
  digitalWrite(_enable_pin, LOW);
  delayMicroseconds(100);   // commands need > 37us to settle
}

void LiquidCrystalRus::writeNbits(uint8_t value, uint8_t n) {
  for (int i = 0; i < n; i++) {
    pinMode(_data_pins[i], OUTPUT);
    digitalWrite(_data_pins[i], (value >> i) & 0x01);
  }

  pulseEnable();
}

uint8_t LiquidCrystalRus::readNbits(uint8_t n) {
  uint8_t retval=0;
  for (int i = 0; i < n; i++) {
    pinMode(_data_pins[i], INPUT);
  }

  digitalWrite(_enable_pin, LOW);
  delayMicroseconds(1);
  digitalWrite(_enable_pin, HIGH);
  delayMicroseconds(1);    // enable pulse must be >450ns

  for (int i = 0; i < n; i++) {
    retval |= (digitalRead(_data_pins[i]) == HIGH)?(1 << i):0;
  }

  digitalWrite(_enable_pin, LOW);

  return retval;
}


/**
 * @file  DirSelectFilesDlg.cpp
 *
 * @brief Implementation of the DirSelectFilesDlg dialog.
 */

#include "stdafx.h"
#include "DirSelectFilesDlg.h"
#include "TrDialogs.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

class DirSelectFilesDlg::Impl : public CTrDialog
{
// Construction
public:
	explicit Impl(DirSelectFilesDlg *p, CWnd* pParent = nullptr);   // standard constructor

// Dialog Data
	enum { IDD = IDD_SELECT_FILES_OR_FOLDERS };

// Overrides
	// ClassWizard generated virtual function overrides
	protected:
	virtual BOOL OnInitDialog() override;
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:

	// Generated message map functions
		// NOTE: the ClassWizard will add member functions here
	afx_msg void OnBnClicked(UINT id);
	afx_msg void OnBnClickedResetButton();
	DECLARE_MESSAGE_MAP()

private:
	void UpdateButtonCaptions();
	DirSelectFilesDlg *m_p;
};

// DirSelectFilesDlg dialog

/**
 * @brief Constructor.
 */
DirSelectFilesDlg::Impl::Impl(DirSelectFilesDlg *p, CWnd* pParent /*= nullptr*/)
	: CTrDialog(DirSelectFilesDlg::Impl::IDD, pParent), m_p(p)
{
}

void DirSelectFilesDlg::Impl::DoDataExchange(CDataExchange* pDX)
{
	CTrDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(DirSelectFilesDlg::Impl, CTrDialog)
		// NOTE: the ClassWizard will add message map macros here
	ON_CONTROL_RANGE(BN_CLICKED, IDC_LEFT1, IDC_LEFT1 + 3 * 3, OnBnClicked)
	ON_BN_CLICKED(IDC_RESET, OnBnClickedResetButton)
END_MESSAGE_MAP()

// DirSelectFilesDlg message handlers

BOOL DirSelectFilesDlg::Impl::OnInitDialog()
{
	CenterWindow();
	LangTranslateDialog(m_hWnd);
	CDialog::OnInitDialog();
	for (int i = 0; i < 3; ++i)
	{
		if (m_p->m_pdi[i])
			SetDlgItemText(IDC_FIRST + i, m_p->m_pdi[i]->diffFileInfo[0].GetFile());
		for (int j = 0; j < 3; ++j)
			GetDlgItem(IDC_LEFT1 + i * 3 + j)->ShowWindow(m_p->m_pdi[i] && m_p->m_pdi[i]->diffcode.exists(j));
	}
	return true;
}

{
	std::vector<int>& selectedButtons = m_p->m_selectedButtons;
	String text;
	GetDlgItemText(id, text);
	if (!text.empty())
		selectedButtons.erase(std::find(selectedButtons.begin(), selectedButtons.end(), static_cast<int>(id - IDC_LEFT1)));
	else
		selectedButtons.push_back(id - IDC_LEFT1);
	if (selectedButtons.size() > 3)
		selectedButtons.erase(selectedButtons.begin());
	UpdateButtonCaptions();
}

void DirSelectFilesDlg::Impl::OnBnClickedResetButton()
{
	m_p->m_selectedButtons.clear();
	UpdateButtonCaptions();
}

void DirSelectFilesDlg::Impl::UpdateButtonCaptions()
{
	for (int i = 0; i < 9; ++i)
	{
		SetDlgItemText(IDC_LEFT1 + i, _T(""));
	}
	int c = 1;
	for (int i: m_p->m_selectedButtons)
	{
		SetDlgItemText(IDC_LEFT1 + i, strutils::to_str(c));
		++c;
	}
}

DirSelectFilesDlg::DirSelectFilesDlg() : m_pimpl(new DirSelectFilesDlg::Impl(this)) {}
DirSelectFilesDlg::~DirSelectFilesDlg() {}
int DirSelectFilesDlg::DoModal() { return static_cast<int>(m_pimpl->DoModal()); }


{
	CenterWindow();
	LangTranslateDialog(m_hWnd);
	CDialog::OnInitDialog();
	for (int i = 0; i < 3; ++i)
	{
		if (m_p->m_pdi[i])
			SetDlgItemText(IDC_FIRST + i, m_p->m_pdi[i]->diffFileInfo[0].GetFile());
		for (int j = 0; j < 3; ++j)
			GetDlgItem(IDC_LEFT1 + i * 3 + j)->ShowWindow(m_p->m_pdi[i] && m_p->m_pdi[i]->diffcode.exists(j));
	}
	return true;
}

/**
 * @file  DirSelectFilesDlg.cpp
 *
 * @brief Implementation of the DirSelectFilesDlg dialog.
 */

#include "stdafx.h"
#include "DirSelectFilesDlg.h"
#include "TrDialogs.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

class DirSelectFilesDlg::Impl : public CTrDialog
{
// Construction
public:
	explicit Impl(DirSelectFilesDlg *p, CWnd* pParent = nullptr);   // standard constructor

// Dialog Data
	enum { IDD = IDD_SELECT_FILES_OR_FOLDERS };

// Overrides
	// ClassWizard generated virtual function overrides
	protected:
	virtual BOOL OnInitDialog() override;
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:

	// Generated message map functions
		// NOTE: the ClassWizard will add member functions here
	afx_msg void OnBnClicked(UINT id);
	afx_msg void OnBnClickedResetButton();
	DECLARE_MESSAGE_MAP()

private:
	void UpdateButtonCaptions();
	DirSelectFilesDlg *m_p;
};

// DirSelectFilesDlg dialog

/**
 * @brief Constructor.
 */
DirSelectFilesDlg::Impl::Impl(DirSelectFilesDlg *p, CWnd* pParent /*= nullptr*/)
	: CTrDialog(DirSelectFilesDlg::Impl::IDD, pParent), m_p(p)
{
}

void DirSelectFilesDlg::Impl::DoDataExchange(CDataExchange* pDX)
{
	CTrDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(DirSelectFilesDlg::Impl, CTrDialog)
		// NOTE: the ClassWizard will add message map macros here
	ON_CONTROL_RANGE(BN_CLICKED, IDC_LEFT1, IDC_LEFT1 + 3 * 3, OnBnClicked)
	ON_BN_CLICKED(IDC_RESET, OnBnClickedResetButton)
END_MESSAGE_MAP()

// DirSelectFilesDlg message handlers

BOOL DirSelectFilesDlg::Impl::OnInitDialog()

void DirSelectFilesDlg::Impl::OnBnClicked(UINT id)
{
	std::vector<int>& selectedButtons = m_p->m_selectedButtons;
	String text;
	GetDlgItemText(id, text);
	if (!text.empty())
		selectedButtons.erase(std::find(selectedButtons.begin(), selectedButtons.end(), static_cast<int>(id - IDC_LEFT1)));
	else
		selectedButtons.push_back(id - IDC_LEFT1);
	if (selectedButtons.size() > 3)
		selectedButtons.erase(selectedButtons.begin());
	UpdateButtonCaptions();
}

void DirSelectFilesDlg::Impl::OnBnClickedResetButton()
{
	m_p->m_selectedButtons.clear();
	UpdateButtonCaptions();
}

void DirSelectFilesDlg::Impl::UpdateButtonCaptions()
{
	for (int i = 0; i < 9; ++i)
	{
		SetDlgItemText(IDC_LEFT1 + i, _T(""));
	}
	int c = 1;
	for (int i: m_p->m_selectedButtons)
	{
		SetDlgItemText(IDC_LEFT1 + i, strutils::to_str(c));
		++c;
	}
}

DirSelectFilesDlg::DirSelectFilesDlg() : m_pimpl(new DirSelectFilesDlg::Impl(this)) {}
DirSelectFilesDlg::~DirSelectFilesDlg() {}
int DirSelectFilesDlg::DoModal() { return static_cast<int>(m_pimpl->DoModal()); }


/**
 * @file  DirSelectFilesDlg.cpp
 *
 * @brief Implementation of the DirSelectFilesDlg dialog.
 */

#include "stdafx.h"
#include "DirSelectFilesDlg.h"
#include "TrDialogs.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

class DirSelectFilesDlg::Impl : public CTrDialog
{
// Construction
public:
	explicit Impl(DirSelectFilesDlg *p, CWnd* pParent = nullptr);   // standard constructor

// Dialog Data
	enum { IDD = IDD_SELECT_FILES_OR_FOLDERS };

// Overrides
	// ClassWizard generated virtual function overrides
	protected:
	virtual BOOL OnInitDialog() override;
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:

	// Generated message map functions
		// NOTE: the ClassWizard will add member functions here
	afx_msg void OnBnClicked(UINT id);
	afx_msg void OnBnClickedResetButton();
	DECLARE_MESSAGE_MAP()

private:
	void UpdateButtonCaptions();
	DirSelectFilesDlg *m_p;
};

// DirSelectFilesDlg dialog

/**
 * @brief Constructor.
 */
DirSelectFilesDlg::Impl::Impl(DirSelectFilesDlg *p, CWnd* pParent /*= nullptr*/)
	: CTrDialog(DirSelectFilesDlg::Impl::IDD, pParent), m_p(p)
{
}

void DirSelectFilesDlg::Impl::DoDataExchange(CDataExchange* pDX)
{
	CTrDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(DirSelectFilesDlg::Impl, CTrDialog)
		// NOTE: the ClassWizard will add message map macros here
	ON_CONTROL_RANGE(BN_CLICKED, IDC_LEFT1, IDC_LEFT1 + 3 * 3, OnBnClicked)
	ON_BN_CLICKED(IDC_RESET, OnBnClickedResetButton)
END_MESSAGE_MAP()

// DirSelectFilesDlg message handlers

BOOL DirSelectFilesDlg::Impl::OnInitDialog()
{
	CenterWindow();
	LangTranslateDialog(m_hWnd);
	CDialog::OnInitDialog();
	for (int i = 0; i < 3; ++i)
	{
		if (m_p->m_pdi[i])
			SetDlgItemText(IDC_FIRST + i, m_p->m_pdi[i]->diffFileInfo[0].GetFile());
		for (int j = 0; j < 3; ++j)
			GetDlgItem(IDC_LEFT1 + i * 3 + j)->ShowWindow(m_p->m_pdi[i] && m_p->m_pdi[i]->diffcode.exists(j));
	}
	return true;
}

void DirSelectFilesDlg::Impl::OnBnClicked(UINT id)
{
	std::vector<int>& selectedButtons = m_p->m_selectedButtons;
	String text;
	GetDlgItemText(id, text);
	if (!text.empty())
		selectedButtons.erase(std::find(selectedButtons.begin(), selectedButtons.end(), static_cast<int>(id - IDC_LEFT1)));
	else
		selectedButtons.push_back(id - IDC_LEFT1);
	if (selectedButtons.size() > 3)
		selectedButtons.erase(selectedButtons.begin());
	Up

}

void DirSelectFilesDlg::Impl::OnBnClickedResetButton()
{
	m_p->m_selectedButtons.clear();
	UpdateButtonCaptions();
}

void DirSelectFilesDlg::Impl::UpdateButtonCaptions()
{
	for (int i = 0; i < 9; ++i)
	{
		SetDlgItemText(IDC_LEFT1 + i, _T(""));
	}
	int c = 1;
	for (int i: m_p->m_selectedButtons)
	{
		SetDlgItemText(IDC_LEFT1 + i, strutils::to_str(c));
		++c;
	}
}

DirSelectFilesDlg::DirSelectFilesDlg() : m_pimpl(new DirSelectFilesDlg::Impl(this)) {}
DirSelectFilesDlg::~DirSelectFilesDlg() {}
int DirSelectFilesDlg::DoModal() { return static_cast<int>(m_pimpl->DoModal()); }


DirSelectFilesDlg::Impl::Impl(DirSelectFilesDlg *p, CWnd* pParent /*= nullptr*/)
	: CTrDialog(DirSelectFilesDlg::Impl::IDD, pParent), m_p(p)
{
}

/**
 * @file  DirSelectFilesDlg.cpp
 *
 * @brief Implementation of the DirSelectFilesDlg dialog.
 */

#include "stdafx.h"
#include "DirSelectFilesDlg.h"
#include "TrDialogs.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

class DirSelectFilesDlg::Impl : public CTrDialog
{
// Construction
public:
	explicit Impl(DirSelectFilesDlg *p, CWnd* pParent = nullptr);   // standard constructor

// Dialog Data
	enum { IDD = IDD_SELECT_FILES_OR_FOLDERS };

// Overrides
	// ClassWizard generated virtual function overrides
	protected:
	virtual BOOL OnInitDialog() override;
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:

	// Generated message map functions
		// NOTE: the ClassWizard will add member functions here
	afx_msg void OnBnClicked(UINT id);
	afx_msg void OnBnClickedResetButton();
	DECLARE_MESSAGE_MAP()

private:
	void UpdateButtonCaptions();
	DirSelectFilesDlg *m_p;
};

// DirSelectFilesDlg dialog

/**
 * @brief Constructor.
 */

void DirSelectFilesDlg::Impl::DoDataExchange(CDataExchange* pDX)
{
	CTrDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(DirSelectFilesDlg::Impl, CTrDialog)
		// NOTE: the ClassWizard will add message map macros here
	ON_CONTROL_RANGE(BN_CLICKED, IDC_LEFT1, IDC_LEFT1 + 3 * 3, OnBnClicked)
	ON_BN_CLICKED(IDC_RESET, OnBnClickedResetButton)
END_MESSAGE_MAP()

// DirSelectFilesDlg message handlers

BOOL DirSelectFilesDlg::Impl::OnInitDialog()
{
	CenterWindow();
	LangTranslateDialog(m_hWnd);
	CDialog::OnInitDialog();
	for (int i = 0; i < 3; ++i)
	{
		if (m_p->m_pdi[i])
			SetDlgItemText(IDC_FIRST + i, m_p->m_pdi[i]->diffFileInfo[0].GetFile());
		for (int j = 0; j < 3; ++j)
			GetDlgItem(IDC_LEFT1 + i * 3 + j)->ShowWindow(m_p->m_pdi[i] && m_p->m_pdi[i]->diffcode.exists(j));
	}
	return true;
}

void DirSelectFilesDlg::Impl::OnBnClicked(UINT id)
{
	std::vector<int>& selectedButtons = m_p->m_selectedButtons;
	String text;
	GetDlgItemText(id, text);
	if (!text.empty())
		selectedButtons.erase(std::find(selectedButtons.begin(), selectedButtons.end(), static_cast<int>(id - IDC_LEFT1)));
	else
		selectedButtons.push_back(id - IDC_LEFT1);
	if (selectedButtons.size() > 3)
		selectedButtons.erase(selectedButtons.begin());
	UpdateButtonCaptions();
}

void DirSelectFilesDlg::Impl::OnBnClickedResetButton()
{
	m_p->m_selectedButtons.clear();
	UpdateButtonCaptions();
}

void DirSelectFilesDlg::Impl::UpdateButtonCaptions()
{
	for (int i = 0; i < 9; ++i)
	{
		SetDlgItemText(IDC_LEFT1 + i, _T(""));
	}
	int c = 1;
	for (int i: m_p->m_selectedButtons)
	{
		SetDlgItemText(IDC_LEFT1 + i, strutils::to_str(c));
		++c;
	}
}

DirSelectFilesDlg::DirSelectFilesDlg() : m_pimpl(new DirSelectFilesDlg::Impl(this)) {}
DirSelectFilesDlg::~DirSelectFilesDlg() {}
int DirSelectFilesDlg::DoModal() { return static_cast<int>(m_pimpl->DoModal()); }


void LLC::write_serialization(uint8_t* buffer, uint32_t total_sz)

/*
 * All rights reserved.
 *
 *
 */

#include <cstring>
#include <tins/llc.h>
#include <tins/stp.h>
#include <tins/rawpdu.h>
#include <tins/exceptions.h>
#include <tins/memory_helpers.h>

using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;

namespace Tins {

const uint8_t LLC::GLOBAL_DSAP_ADDR = 0xFF;
const uint8_t LLC::NULL_ADDR = 0x00;

LLC::LLC()
: header_(), control_field(), type_(LLC::INFORMATION) {
	control_field_length_ = 2;
	information_field_length_ = 0;
}

LLC::LLC(uint8_t dsap, uint8_t ssap)
: control_field(), type_(LLC::INFORMATION) {
	header_.dsap = dsap;
	header_.ssap = ssap;
	control_field_length_ = 2;
	information_field_length_ = 0;
}

LLC::LLC(const uint8_t* buffer, uint32_t total_sz) {
    InputMemoryStream stream(buffer, total_sz);
    stream.read(header_);
    if (!stream) {
        throw malformed_packet();
    }
	information_field_length_ = 0;
	if ((*stream.pointer() & 0x03) == LLC::UNNUMBERED) {
		type(LLC::UNNUMBERED);
        stream.read(control_field.unnumbered);
		// TODO: Create information fields if corresponding.
	}
	else {
		type((Format)(*stream.pointer() & 0x03));
		control_field_length_ = 2;
		stream.read(control_field.info);
	}
    if (stream) {
        if (dsap() == 0x42 && ssap() == 0x42) {
            inner_pdu(new Tins::STP(stream.pointer(), stream.size()));
        }
        else {
            inner_pdu(new Tins::RawPDU(stream.pointer(), stream.size()));
        }
    }
}

void LLC::group(bool value) {
	if (value) {
		header_.dsap |= 0x01;
	}
	else {
		header_.dsap &= 0xFE;
	}
}

void LLC::dsap(uint8_t new_dsap) {
	header_.dsap = new_dsap;
}

void LLC::response(bool value) {
	if (value) {
		header_.ssap |= 0x01;
	}
	else {
		header_.ssap &= 0xFE;
	}
}

void LLC::ssap(uint8_t new_ssap) {
	header_.ssap = new_ssap;
}

void LLC::type(LLC::Format type) {
	type_ = type;
	switch (type) {
		case LLC::INFORMATION:
			control_field_length_ = 2;
			control_field.info.type_bit = 0;
			break;
		case LLC::SUPERVISORY:
			control_field_length_ = 2;
			control_field.super.type_bit = 1;
			break;
		case LLC::UNNUMBERED:
			control_field_length_ = 1;
			control_field.unnumbered.type_bits = 3;
			break;
	}
}

void LLC::send_seq_number(uint8_t seq_number) {
	if (type() != LLC::INFORMATION) {
		return;
    }
	control_field.info.send_seq_num = seq_number;
}

void LLC::receive_seq_number(uint8_t seq_number) {
	switch (type()) {
		case LLC::UNNUMBERED:
			return;
		case LLC::INFORMATION:
			control_field.info.recv_seq_num = seq_number;
			break;
		case LLC::SUPERVISORY:
			control_field.super.recv_seq_num = seq_number;
			break;
	}
}

void LLC::poll_final(bool value) {
	switch (type()) {
		case LLC::UNNUMBERED:
			control_field.unnumbered.poll_final_bit = value;
			break;
		case LLC::INFORMATION:
			control_field.info.poll_final_bit = value;
			return;
		case LLC::SUPERVISORY:
			control_field.super.poll_final_bit = value;
			break;
	}

}

void LLC::supervisory_function(LLC::SupervisoryFunctions new_func) {
	if (type() != LLC::SUPERVISORY) {
		return;
    }
	control_field.super.supervisory_func = new_func;
}

void LLC::modifier_function(LLC::ModifierFunctions mod_func) {
	if (type() != LLC::UNNUMBERED) {
		return;
    }
	control_field.unnumbered.mod_func1 = mod_func >> 3;
	control_field.unnumbered.mod_func2 = mod_func & 0x07;
}

void LLC::add_xid_information(uint8_t xid_id, uint8_t llc_type_class, uint8_t receive_window) {
    field_type xid(3);
    xid[0] = xid_id;
    xid[1] = llc_type_class;
    xid[2] = receive_window;
	information_field_length_ += static_cast<uint8_t>(xid.size());
    information_fields_.push_back(xid);
}

uint32_t LLC::header_size() const {
	return sizeof(header_) + control_field_length_ + information_field_length_;
}

void LLC::clear_information_fields() {
	information_field_length_ = 0;
	information_fields_.clear();
}

{
    OutputMemoryStream stream(buffer, total_sz);
    if (inner_pdu() && inner_pdu()->pdu_type() == PDU::STP) {
        dsap(0x42);
        ssap(0x42);
    }
    stream.write(header_);
	switch (type()) {
		case LLC::UNNUMBERED:
            stream.write(control_field.unnumbered);
			break;
		case LLC::INFORMATION:
            stream.write(control_field.info);
			break;
		case LLC::SUPERVISORY:
            stream.write(control_field.super);
			break;
	}

	for (field_list::const_iterator it = information_fields_.begin(); it != information_fields_.end(); ++it) {
        stream.write(it->begin(), it->end());
	}
}

} // Tins


{
	type_ = type;
	switch (type) {
		case LLC::INFORMATION:
			control_field_length_ = 2;
			control_field.info.type_bit = 0;
			break;
		case LLC::SUPERVISORY:
			control_field_length_ = 2;
			control_field.super.type_bit = 1;
			break;
		case LLC::UNNUMBERED:
			control_field_length_ = 1;
			control_field.unnumbered.type_bits = 3;
			break;
	}
}

/*
 * All rights reserved.
 *
 *
 */

#include <cstring>
#include <tins/llc.h>
#include <tins/stp.h>
#include <tins/rawpdu.h>
#include <tins/exceptions.h>
#include <tins/memory_helpers.h>

using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;

namespace Tins {

const uint8_t LLC::GLOBAL_DSAP_ADDR = 0xFF;
const uint8_t LLC::NULL_ADDR = 0x00;

LLC::LLC()
: header_(), control_field(), type_(LLC::INFORMATION) {
	control_field_length_ = 2;
	information_field_length_ = 0;
}

LLC::LLC(uint8_t dsap, uint8_t ssap)
: control_field(), type_(LLC::INFORMATION) {
	header_.dsap = dsap;
	header_.ssap = ssap;
	control_field_length_ = 2;
	information_field_length_ = 0;
}

LLC::LLC(const uint8_t* buffer, uint32_t total_sz) {
    InputMemoryStream stream(buffer, total_sz);
    stream.read(header_);
    if (!stream) {
        throw malformed_packet();
    }
	information_field_length_ = 0;
	if ((*stream.pointer() & 0x03) == LLC::UNNUMBERED) {
		type(LLC::UNNUMBERED);
        stream.read(control_field.unnumbered);
		// TODO: Create information fields if corresponding.
	}
	else {
		type((Format)(*stream.pointer() & 0x03));
		control_field_length_ = 2;
		stream.read(control_field.info);
	}
    if (stream) {
        if (dsap() == 0x42 && ssap() == 0x42) {
            inner_pdu(new Tins::STP(stream.pointer(), stream.size()));
        }
        else {
            inner_pdu(new Tins::RawPDU(stream.pointer(), stream.size()));
        }
    }
}

void LLC::group(bool value) {
	if (value) {
		header_.dsap |= 0x01;
	}
	else {
		header_.dsap &= 0xFE;
	}
}

void LLC::dsap(uint8_t new_dsap) {
	header_.dsap = new_dsap;
}

void LLC::response(bool value) {
	if (value) {
		header_.ssap |= 0x01;
	}
	else {
		header_.ssap &= 0xFE;
	}
}

void LLC::ssap(uint8_t new_ssap) {
	header_.ssap = new_ssap;
}

void LLC::type(LLC::Format type)

void LLC::send_seq_number(uint8_t seq_number) {
	if (type() != LLC::INFORMATION) {
		return;
    }
	control_field.info.send_seq_num = seq_number;
}

void LLC::receive_seq_number(uint8_t seq_number) {
	switch (type()) {
		case LLC::UNNUMBERED:
			return;
		case LLC::INFORMATION:
			control_field.info.recv_seq_num = seq_number;
			break;
		case LLC::SUPERVISORY:
			control_field.super.recv_seq_num = seq_number;
			break;
	}
}

void LLC::poll_final(bool value) {
	switch (type()) {
		case LLC::UNNUMBERED:
			control_field.unnumbered.poll_final_bit = value;
			break;
		case LLC::INFORMATION:
			control_field.info.poll_final_bit = value;
			return;
		case LLC::SUPERVISORY:
			control_field.super.poll_final_bit = value;
			break;
	}

}

void LLC::supervisory_function(LLC::SupervisoryFunctions new_func) {
	if (type() != LLC::SUPERVISORY) {
		return;
    }
	control_field.super.supervisory_func = new_func;
}

void LLC::modifier_function(LLC::ModifierFunctions mod_func) {
	if (type() != LLC::UNNUMBERED) {
		return;
    }
	control_field.unnumbered.mod_func1 = mod_func >> 3;
	control_field.unnumbered.mod_func2 = mod_func & 0x07;
}

void LLC::add_xid_information(uint8_t xid_id, uint8_t llc_type_class, uint8_t receive_window) {
    field_type xid(3);
    xid[0] = xid_id;
    xid[1] = llc_type_class;
    xid[2] = receive_window;
	information_field_length_ += static_cast<uint8_t>(xid.size());
    information_fields_.push_back(xid);
}

uint32_t LLC::header_size() const {
	return sizeof(header_) + control_field_length_ + information_field_length_;
}

void LLC::clear_information_fields() {
	information_field_length_ = 0;
	information_fields_.clear();
}

void LLC::write_serialization(uint8_t* buffer, uint32_t total_sz) {
    OutputMemoryStream stream(buffer, total_sz);
    if (inner_pdu() && inner_pdu()->pdu_type() == PDU::STP) {
        dsap(0x42);
        ssap(0x42);
    }
    stream.write(header_);
	switch (type()) {
		case LLC::UNNUMBERED:
            stream.write(control_field.unnumbered);
			break;
		case LLC::INFORMATION:
            stream.write(control_field.info);
			break;
		case LLC::SUPERVISORY:
            stream.write(control_field.super);
			break;
	}

	for (field_list::const_iterator it = information_fields_.begin(); it != information_fields_.end(); ++it) {
        stream.write(it->begin(), it->end());
	}
}

} // Tins


/*
 * All rights reserved.
 *
 *
 */

#include <cstring>
#include <tins/llc.h>
#include <tins/stp.h>
#include <tins/rawpdu.h>
#include <tins/exceptions.h>
#include <tins/memory_helpers.h>

using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;

namespace Tins {

const uint8_t LLC::GLOBAL_DSAP_ADDR = 0xFF;
const uint8_t LLC::NULL_ADDR = 0x00;

LLC::LLC()
: header_(), control_field(), type_(LLC::INFORMATION) {
	control_field_length_ = 2;
	information_field_length_ = 0;
}

LLC::LLC(uint8_t dsap, uint8_t ssap)
: control_field(), type_(LLC::INFORMATION) {
	header_

	header_.ssap = ssap;
	control_field_length_ = 2;
	information_field_length_ = 0;
}

LLC::LLC(const uint8_t* buffer, uint32_t total_sz) {
    InputMemoryStream stream(buffer, total_sz);
    stream.read(header_);
    if (!stream) {
        throw malformed_packet();
    }
	information_field_length_ = 0;
	if ((*stream.pointer() & 0x03) == LLC::UNNUMBERED) {
		type(LLC::UNNUMBERED);
        stream.read(control_field.unnumbered);
		// TODO: Create information fields if corresponding.
	}
	else {
		type((Format)(*stream.pointer() & 0x03));
		control_field_length_ = 2;
		stream.read(control_field.info);
	}
    if (stream) {
        if (dsap() == 0x42 && ssap() == 0x42) {
            inner_pdu(new Tins::STP(stream.pointer(), stream.size()));
        }
        else {
            inner_pdu(new Tins::RawPDU(stream.pointer(), stream.size()));
        }
    }
}

void LLC::group(bool value) {
	if (value) {
		header_.dsap |= 0x01;
	}
	else {
		header_.dsap &= 0xFE;
	}
}

void LLC::dsap(uint8_t new_dsap) {
	header_.dsap = new_dsap;
}

void LLC::response(bool value) {
	if (value) {
		header_.ssap |= 0x01;
	}
	else {
		header_.ssap &= 0xFE;
	}
}

void LLC::ssap(uint8_t new_ssap) {
	header_.ssap = new_ssap;
}

void LLC::type(LLC::Format type) {
	type_ = type;
	switch (type) {
		case LLC::INFORMATION:
			control_field_length_ = 2;
			control_field.info.type_bit = 0;
			break;
		case LLC::SUPERVISORY:
			control_field_length_ = 2;
			control_field.super.type_bit = 1;
			break;
		case LLC::UNNUMBERED:
			control_field_length_ = 1;
			control_field.unnumbered.type_bits = 3;
			break;
	}
}

void LLC::send_seq_number(uint8_t seq_number) {
	if (type() != LLC::INFORMATION) {
		return;
    }
	control_field.info.send_seq_num = seq_number;
}

void LLC::receive_seq_number(uint8_t seq_number) {
	switch (type()) {
		case LLC::UNNUMBERED:
			return;
		case LLC::INFORMATION:
			control_field.info.recv_seq_num = seq_number;
			break;
		case LLC::SUPERVISORY:
			control_field.super.recv_seq_num = seq_number;
			break;
	}
}

void LLC::poll_final(bool value) {
	switch (type()) {
		case LLC::UNNUMBERED:
			control_field.unnumbered.poll_final_bit = value;
			break;
		case LLC::INFORMATION:
			control_field.info.poll_final_bit = value;
			return;
		case LLC::SUPERVISORY:
			control_field.super.poll_final_bit = value;
			break;
	}

}

void LLC::supervisory_function(LLC::SupervisoryFunctions new_func) {
	if (type() != LLC::SUPERVISORY) {
		return;
    }
	control_field.super.supervisory_func = new_func;
}

void LLC::modifier_function(LLC::ModifierFunctions mod_func) {
	if (type() != LLC::UNNUMBERED) {
		return;
    }
	control_field.unnumbered.mod_func1 = mod_func >> 3;
	control_field.unnumbered.mod_func2 = mod_func & 0x07;
}

void LLC::add_xid_information(uint8_t xid_id, uint8_t llc_type_class, uint8_t receive_window) {
    field_type xid(3);
    xid[0] = xid_id;
    xid[1] = llc_type_class;
    xid[2] = receive_window;
	information_field_length_ += static_cast<uint8_t>(xid.size());
    information_fields_.push_back(xid);
}

uint32_t LLC::header_size() const {
	return sizeof(header_) + control_field_length_ + information_field_length_;
}

void LLC::clear_information_fields() {
	information_field_length_ = 0;
	information_fields_.clear();
}

void LLC::write_serialization(uint8_t* buffer, uint32_t total_sz) {
    OutputMemoryStream stream(buffer, total_sz);
    if (inner_pdu() && inner_pdu()->pdu_type() == PDU::STP) {
        dsap(0x42);
        ssap(0x42);
    }
    stream.write(header_);
	switch (type()) {
		case LLC::UNNUMBERED:
            stream.write(control_field.unnumbered);
			break;
		case LLC::INFORMATION:
            stream.write(control_field.info);
			break;
		case LLC::SUPERVISORY:
            stream.write(control_field.super);
			break;
	}

	for (field_list::const_iterator it = information_fields_.begin(); it != information_fields_.end(); ++it) {
        stream.write(it->begin(), it->end());
	}
}

} // Tins


switch (type) {
		case LLC::INFORMATION:
			control_field_length_ = 2;
			control_field.info.type_bit = 0;
			break;
		case LLC::SUPERVISORY:
			control_field_length_ = 2;
			control_field.super.type_bit = 1;
			break;
		case LLC::UNNUMBERED:
			control_field_length_ = 1;
			control_field.unnumbered.type_bits = 3;
			break;
	}

/*
 * All rights reserved.
 *
 *
 */

#include <cstring>
#include <tins/llc.h>
#include <tins/stp.h>
#include <tins/rawpdu.h>
#include <tins/exceptions.h>
#include <tins/memory_helpers.h>

using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;

namespace Tins {

const uint8_t LLC::GLOBAL_DSAP_ADDR = 0xFF;
const uint8_t LLC::NULL_ADDR = 0x00;

LLC::LLC()
: header_(), control_field(), type_(LLC::INFORMATION) {
	control_field_length_ = 2;
	information_field_length_ = 0;
}

LLC::LLC(uint8_t dsap, uint8_t ssap)
: control_field(), type_(LLC::INFORMATION) {
	header_.dsap = dsap;
	header_.ssap = ssap;
	control_field_length_ = 2;
	information_field_length_ = 0;
}

LLC::LLC(const uint8_t* buffer, uint32_t total_sz) {
    InputMemoryStream stream(buffer, total_sz);
    stream.read(header_);
    if (!stream) {
        throw malformed_packet();
    }
	information_field_length_ = 0;
	if ((*stream.pointer() & 0x03) == LLC::UNNUMBERED) {
		type(LLC::UNNUMBERED);
        stream.read(control_field.unnumbered);
		// TODO: Create information fields if corresponding.
	}
	else {
		type((Format)(*stream.pointer() & 0x03));
		control_field_length_ = 2;
		stream.read(control_field.info);
	}
    if (stream) {
        if (dsap() == 0x42 && ssap() == 0x42) {
            inner_pdu(new Tins::STP(stream.pointer(), stream.size()));
        }
        else {
            inner_pdu(new Tins::RawPDU(stream.pointer(), stream.size()));
        }
    }
}

void LLC::group(bool value) {
	if (value) {
		header_.dsap |= 0x01;
	}
	else {
		header_.dsap &= 0xFE;
	}
}

void LLC::dsap(uint8_t new_dsap) {
	header_.dsap = new_dsap;
}

void LLC::response(bool value) {
	if (value) {
		header_.ssap |= 0x01;
	}
	else {
		header_.ssap &= 0xFE;
	}
}

void LLC::ssap(uint8_t new_ssap) {
	header_.ssap = new_ssap;
}

void LLC::type(LLC::Format type) {
	type_ = type;

}

void LLC::send_seq_number(uint8_t seq_number) {
	if (type() != LLC::INFORMATION) {
		return;
    }
	control_field.info.send_seq_num = seq_number;
}

void LLC::receive_seq_number(uint8_t seq_number) {
	switch (type()) {
		case LLC::UNNUMBERED:
			return;
		case LLC::INFORMATION:
			control_field.info.recv_seq_num = seq_number;
			break;
		case LLC::SUPERVISORY:
			control_field.super.recv_seq_num = seq_number;
			break;
	}
}

void LLC::poll_final(bool value) {
	switch (type()) {
		case LLC::UNNUMBERED:
			control_field.unnumbered.poll_final_bit = value;
			break;
		case LLC::INFORMATION:
			control_field.info.poll_final_bit = value;
			return;
		case LLC::SUPERVISORY:
			control_field.super.poll_final_bit = value;
			break;
	}

}

void LLC::supervisory_function(LLC::SupervisoryFunctions new_func) {
	if (type() != LLC::SUPERVISORY) {
		return;
    }
	control_field.super.supervisory_func = new_func;
}

void LLC::modifier_function(LLC::ModifierFunctions mod_func) {
	if (type() != LLC::UNNUMBERED) {
		return;
    }
	control_field.unnumbered.mod_func1 = mod_func >> 3;
	control_field.unnumbered.mod_func2 = mod_func & 0x07;
}

void LLC::add_xid_information(uint8_t xid_id, uint8_t llc_type_class, uint8_t receive_window) {
    field_type xid(3);
    xid[0] = xid_id;
    xid[1] = llc_type_class;
    xid[2] = receive_window;
	information_field_length_ += static_cast<uint8_t>(xid.size());
    information_fields_.push_back(xid);
}

uint32_t LLC::header_size() const {
	return sizeof(header_) + control_field_length_ + information_field_length_;
}

void LLC::clear_information_fields() {
	information_field_length_ = 0;
	information_fields_.clear();
}

void LLC::write_serialization(uint8_t* buffer, uint32_t total_sz) {
    OutputMemoryStream stream(buffer, total_sz);
    if (inner_pdu() && inner_pdu()->pdu_type() == PDU::STP) {
        dsap(0x42);
        ssap(0x42);
    }
    stream.write(header_);
	switch (type()) {
		case LLC::UNNUMBERED:
            stream.write(control_field.unnumbered);
			break;
		case LLC::INFORMATION:
            stream.write(control_field.info);
			break;
		case LLC::SUPERVISORY:
            stream.write(control_field.super);
			break;
	}

	for (field_list::const_iterator it = information_fields_.begin(); it != information_fields_.end(); ++it) {
        stream.write(it->begin(), it->end());
	}
}

} // Tins


// expected-no-diagnostics

#ifndef HEADER
#define HEADER

struct S {
  S(): a(0) {}
  S(int v) : a(v) {}
  int a;
  typedef int type;
};

template <typename T>
class S7 : public T {
protected:
  T a;
  S7() : a(0) {}

public:
  S7(typename T::type v) : a(v) {
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for private(a) private(this->a) private(T::a)
    for (int k = 0; k < a.a; ++k)
      ++this->a.a;
  }
  S7 &operator=(S7 &s) {
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for private(a) private(this->a)
    for (int k = 0; k < s.a.a; ++k)
      ++s.a.a;
    return *this;
  }
};

// CHECK: #pragma omp distribute parallel for private(this->a) private(this->a) private(T::a){{$}}
// CHECK: #pragma omp distribute parallel for private(this->a) private(this->a)
// CHECK: #pragma omp distribute parallel for private(this->a) private(this->a) private(this->S::a)

class S8 : public S7<S> {
  S8() {}

public:
  S8(int v) : S7<S>(v){
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for private(a) private(this->a) private(S7<S>::a)
    for (int k = 0; k < a.a; ++k)
      ++this->a.a;
  }
  S8 &operator=(S8 &s) {
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for private(a) private(this->a)
    for (int k = 0; k < s.a.a; ++k)
      ++s.a.a;
    return *this;
  }
};

// CHECK: #pragma omp distribute parallel for private(this->a) private(this->a) private(this->S7<S>::a)
// CHECK: #pragma omp distribute parallel for private(this->a) private(this->a)

template <class T, int N>
T tmain(T argc) {
  T b = argc, c, d, e, f, h;
  static T a;
  static T g;
#pragma omp threadprivate(g)
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for dist_schedule(static, a) schedule(dynamic) default(none) copyin(g) firstprivate(a) allocate(a)
  // CHECK: #pragma omp distribute parallel for dist_schedule(static, a) schedule(dynamic) default(none) copyin(g) firstprivate(a) allocate(a)
  for (int i = 0; i < 2; ++i)
    a = 2;
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for allocate(argc) private(argc, b), firstprivate(c, d), lastprivate(f) collapse(N) schedule(static, N) if (parallel :argc) num_threads(N) default(shared) shared(e) reduction(+ : h) dist_schedule(static,N)
  for (int i = 0; i < 2; ++i)
    for (int j = 0; j < 2; ++j)
      for (int j = 0; j < 2; ++j)
        for (int j = 0; j < 2; ++j)
          for (int j = 0; j < 2; ++j)
  for (int i = 0; i < 2; ++i)
    for (int j = 0; j < 2; ++j)
      for (int j = 0; j < 2; ++j)
        for (int j = 0; j < 2; ++j)
          for (int j = 0; j < 2; ++j)
            a++;
  // CHECK: #pragma omp distribute parallel for allocate(argc) private(argc,b) firstprivate(c,d) lastprivate(f) collapse(N) schedule(static, N) if(parallel: argc) num_threads(N) default(shared) shared(e) reduction(+: h) dist_schedule(static, N)
  return T();
}

void foo(int argc, char **argv) {
  int b, c, d, e, f, h;
  static int a;
  static float g;
#pragma omp threadprivate(g)
  [&]() {
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for schedule(guided, argc) default(none) copyin(g) dist_schedule(static, a) private(a) shared(argc)
    // CHECK: #pragma omp distribute parallel for schedule(guided, argc) default(none) copyin(g) dist_schedule(static, a) private(a) shared(argc)
    for (int i = 0; i < 2; ++i)
      [&]() {
	  a = 2;
	}();

  }();
  [&]() {
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for private(argc, b), firstprivate(argv, c), lastprivate(d, f) collapse(2) schedule(auto) if (argc) num_threads(a) default(shared) shared(e) reduction(+ : h) dist_schedule(static, b)
    for (int i = 0; i < 10; ++i)
      for (int j = 0; j < 10; ++j)
	[&]() {
	  a++;
	}();
    // CHECK: #pragma omp distribute parallel for private(argc,b) firstprivate(argv,c) lastprivate(d,f) collapse(2) schedule(auto) if(argc) num_threads(a) default(shared) shared(e) reduction(+: h) dist_schedule(static, b)
  }();
}

{
  int b = argc, c, d, e, f, h;
  static int a;
  static float g;
#pragma omp threadprivate(g)
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for schedule(guided, argc) default(none) copyin(g) dist_schedule(static, a) private(a) shared(argc)
  // CHECK: #pragma omp distribute parallel for schedule(guided, argc) default(none) copyin(g) dist_schedule(static, a) private(a) shared(argc)
  for (int i = 0; i < 2; ++i)
    a = 2;
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for private(argc, b), firstprivate(argv, c), lastprivate(d, f) collapse(2) schedule(auto) if (argc) num_threads(a) default(shared) shared(e) reduction(+ : h) dist_schedule(static, b)
  for (int i = 0; i < 10; ++i)
    for (int j = 0; j < 10; ++j)
      a++;
  // CHECK: #pragma omp distribute parallel for private(argc,b) firstprivate(argv,c) lastprivate(d,f) collapse(2) schedule(auto) if(argc) num_threads(a) default(shared) shared(e) reduction(+: h) dist_schedule(static, b)
  return (tmain<int, 5>(argc) + tmain<char, 1>(argv[0][0]));
}

#endif


// expected-no-diagnostics

#ifndef HEADER
#define HEADER

struct S {
  S(): a(0)

  S(int v) : a(v) {}
  int a;
  typedef int type;
};

template <typename T>
class S7 : public T {
protected:
  T a;
  S7() : a(0) {}

public:
  S7(typename T::type v) : a(v) {
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for private(a) private(this->a) private(T::a)
    for (int k = 0; k < a.a; ++k)
      ++this->a.a;
  }
  S7 &operator=(S7 &s) {
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for private(a) private(this->a)
    for (int k = 0; k < s.a.a; ++k)
      ++s.a.a;
    return *this;
  }
};

// CHECK: #pragma omp distribute parallel for private(this->a) private(this->a) private(T::a){{$}}
// CHECK: #pragma omp distribute parallel for private(this->a) private(this->a)
// CHECK: #pragma omp distribute parallel for private(this->a) private(this->a) private(this->S::a)

class S8 : public S7<S> {
  S8() {}

public:
  S8(int v) : S7<S>(v){
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for private(a) private(this->a) private(S7<S>::a)
    for (int k = 0; k < a.a; ++k)
      ++this->a.a;
  }
  S8 &operator=(S8 &s) {
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for private(a) private(this->a)
    for (int k = 0; k < s.a.a; ++k)
      ++s.a.a;
    return *this;
  }
};

// CHECK: #pragma omp distribute parallel for private(this->a) private(this->a) private(this->S7<S>::a)
// CHECK: #pragma omp distribute parallel for private(this->a) private(this->a)

template <class T, int N>
T tmain(T argc) {
  T b = argc, c, d, e, f, h;
  static T a;
  static T g;
#pragma omp threadprivate(g)
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for dist_schedule(static, a) schedule(dynamic) default(none) copyin(g) firstprivate(a) allocate(a)
  // CHECK: #pragma omp distribute parallel for dist_schedule(static, a) schedule(dynamic) default(none) copyin(g) firstprivate(a) allocate(a)
  for (int i = 0; i < 2; ++i)
    a = 2;
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for allocate(argc) private(argc, b), firstprivate(c, d), lastprivate(f) collapse(N) schedule(static, N) if (parallel :argc) num_threads(N) default(shared) shared(e) reduction(+ : h) dist_schedule(static,N)
  for (int i = 0; i < 2; ++i)
    for (int j = 0; j < 2; ++j)
      for (int j = 0; j < 2; ++j)
        for (int j = 0; j < 2; ++j)
          for (int j = 0; j < 2; ++j)
  for (int i = 0; i < 2; ++i)
    for (int j = 0; j < 2; ++j)
      for (int j = 0; j < 2; ++j)
        for (int j = 0; j < 2; ++j)
          for (int j = 0; j < 2; ++j)
            a++;
  // CHECK: #pragma omp distribute parallel for allocate(argc) private(argc,b) firstprivate(c,d) lastprivate(f) collapse(N) schedule(static, N) if(parallel: argc) num_threads(N) default(shared) shared(e) reduction(+: h) dist_schedule(static, N)
  return T();
}

void foo(int argc, char **argv) {
  int b, c, d, e, f, h;
  static int a;
  static float g;
#pragma omp threadprivate(g)
  [&]() {
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for schedule(guided, argc) default(none) copyin(g) dist_schedule(static, a) private(a) shared(argc)
    // CHECK: #pragma omp distribute parallel for schedule(guided, argc) default(none) copyin(g) dist_schedule(static, a) private(a) shared(argc)
    for (int i = 0; i < 2; ++i)
      [&]() {
	  a = 2;
	}();

  }();
  [&]() {
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for private(argc, b), firstprivate(argv, c), lastprivate(d, f) collapse(2) schedule(auto) if (argc) num_threads(a) default(shared) shared(e) reduction(+ : h) dist_schedule(static, b)
    for (int i = 0; i < 10; ++i)
      for (int j = 0; j < 10; ++j)
	[&]() {
	  a++;
	}();
    // CHECK: #pragma omp distribute parallel for private(argc,b) firstprivate(argv,c) lastprivate(d,f) collapse(2) schedule(auto) if(argc) num_threads(a) default(shared) shared(e) reduction(+: h) dist_schedule(static, b)
  }();
}

int main(int argc, char **argv) {
  int b = argc, c, d, e, f, h;
  static int a;
  static float g;
#pragma omp threadprivate(g)
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for schedule(guided, argc) default(none) copyin(g) dist_schedule(static, a) private(a) shared(argc)
  // CHECK: #pragma omp distribute parallel for schedule(guided, argc) default(none) copyin(g) dist_schedule(static, a) private(a) shared(argc)
  for (int i = 0; i < 2; ++i)
    a = 2;
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for private(argc, b), firstprivate(argv, c), lastprivate(d, f) collapse(2) schedule(auto) if (argc) num_threads(a) default(shared) shared(e) reduction(+ : h) dist_schedule(static, b)
  for (int i = 0; i < 10; ++i)
    for (int j = 0; j < 10; ++j)
      a++;
  // CHECK: #pragma omp distribute parallel for private(argc,b) firstprivate(argv,c) lastprivate(d,f) collapse(2) schedule(auto) if(argc) num_threads(a) default(shared) shared(e) reduction(+: h) dist_schedule(static, b)
  return (tmain<int, 5>(argc) + tmain<char, 1>(argv[0][0]));
}

#endif


// expected-no-diagnostics

#ifndef HEADER
#define HEADER

struct S {
  S(): a(0) {}
  S(int v) : a(v) {}
  int a;
  typedef int type;
};

template <typename T>
class S7 : public T {
protected:
  T a;
  S7() : a(0) {}

public:
  S7(typename T::type v) : a(v) {
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for private(a) private(this->a) private(T::a)
    for (int k = 0; k < a.a; ++k)
      ++this->a.a;
  }
  S7 &operator=(S7 &s) {
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for private(a) private(this->a)
    for (int k = 0; k < s.a.a; ++k)
      ++s.a.a;
    return *this;
  }
};

// CHECK: #pragma omp distribute parallel for private(this->a) private(this->a) private(T::a){{$}}
// CHECK: #pragma omp distribute parallel for private(this->a) private(this->a)
// CHECK: #pragma omp distribute parallel for private(this->a) private(this->a) private(this->S::a)

class S8 : public S7<S> {
  S8() {}

public:
  S8(int v) : S7<S>(v){
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for private(a) private(this->a) private(S7<S>::a)
    for (int k = 0; k < a.a; ++k)
      ++this->a.a;
  }
  S8 &operator=(S8 &s) {
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for private(a) private(this->a)
    for (int k = 0; k < s.a.a; ++k)
      ++s.a.a;
    return *this;
  }
};

// CHECK: #pragma omp distribute parallel for private(this->a) private(this->a) private(this->S7<S>::a)
// CHECK: #pragma omp distribute parallel for private(this->a) private(this->a)

template <class T, int N>
T tmain(T argc) {
  T b = argc, c, d, e, f, h;
  static T a;
  static T g;
#pragma omp threadprivate(g)
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for dist_schedule(static, a) schedule(dynamic) default(none) copyin(g) firstprivate(a) allocate(a)
  // CHECK: #pragma omp distribute parallel for dist_schedule(static, a) schedule(dynamic) default(none) copyin(g) firstprivate(a) allocate(a)
  for (int i = 0; i < 2; ++i)
    a = 2;
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for allocate(argc) private(argc, b), firstprivate(c, d), lastprivate(f) collapse(N) schedule(static, N) if (parallel :argc) num_threads(N) default(shared) shared(e) reduction(+ : h) dist_schedule(static,N)
  for (int i = 0; i < 2; ++i)
    for (int j = 0; j < 2; ++j)
      for (int j = 0; j < 2; ++j)
        for (int j = 0; j < 2; ++j)
          for (int j = 0; j < 2; ++j)
  for (int i = 0; i < 2; ++i)
    for (int j = 0; j < 2; ++j)
      for (int j = 0; j < 2; ++j)
        for (int j = 0; j < 2; ++j)
          for (int j = 0; j < 2; ++j)
            a++;
  // CHECK: #pragma omp distribute parallel for allocate(argc) private(argc,b) firstprivate(c,d) lastprivate(f) collapse(N) schedule(static, N) if(parallel: argc) num_threads(N) default(shared) shared(e) reduction(+: h) dist_schedule(static, N)
  return T();
}

void foo(int argc, char **argv) {
  int b, c, d, e, f, h;
  static int a;
  static float g;
#pragma omp threadprivate(g)
  [&]() {
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for schedule(guided, argc) default(none) copyin(g) dist_schedule(static, a) private(a) shared(argc)
    // CHECK: #pragma omp distribute parallel for schedule(guided, argc) default(none) copyin(g) dist_schedule(static, a) private(a) shared(argc)
    for (int i = 0; i < 2; ++i)
      [&]() {
	  a = 2;
	}();

  }();
  [&]() {
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for private(argc, b), firstprivate(argv, c), lastprivate(d, f) collapse(2) schedule(auto) if (argc) num_threads(a) default(shared) shared(e) reduction(+ : h) dist_schedule(static, b)
    for (int i = 0; i < 10; ++i)
      for (int j = 0; j < 10; ++j)
	[&]() {
	  a++;
	}();
    // CHECK: #pragma omp distribute parallel for private(argc,b) firstprivate(argv,c) lastprivate(d,f) collapse(2) schedule(auto) if(argc) num_threads(a) default(shared) shared(e) reduction(+: h) dist_schedule(static, b)
  }();
}

int main(int argc, char **argv) {
  int b = argc, c, d, e, f, h;
  static int a;
  static float g;
#pragma omp threadprivate(g)
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for schedule(guided, argc) default(none) copyin(g) dist_schedule(static, a) private(a) shared(argc)
  // CHECK: #pragma omp distribute parallel for schedule(guided, argc) default(none) copyin(g) dist_schedule(static, a) private(a) shared(argc)
  for (int i = 0; i < 2; ++i)
    a = 2;
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for private(argc, b), firstprivate(argv, c), lastprivate(d, f) collapse(2) schedule(auto) if (argc) num_threads(a) default(shared) shared(e) reduction(+ : h) dist_schedule(static, b)
  for (int i = 0; i < 10; ++i)
    for (int j = 0; j < 10; ++j)
      a++;
  // CHECK: #pragma omp distribute parallel for private(argc,b) firstprivate(argv,c) lastprivate(d,f) collapse(2) schedule(auto) if(argc) num_threads(a) default(shared) shared(e) reduction(+: h) dist_schedule(static, b)
  return (tmain<int, 5>(argc) + tmain<char, 1>(argv


ORDocumentIterator::ORDocumentIterator()
    :pDocIteratorQueue_(NULL)
    ,hasNot_(false)
    ,currDocOfNOTIter_(MAX_DOC_ID)
    ,initNOTIterator_(false)
    ,pNOTDocIterator_(NULL)

#include "ORDocumentIterator.h"
#include "NOTDocumentIterator.h"
#include "VirtualPropertyTermDocumentIterator.h"

#include <algorithm>
#include <limits>

using namespace std;
using namespace sf1r;

{
}

ORDocumentIterator::~ORDocumentIterator()
{
    vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
    for (; iter != docIteratorList_.end(); ++iter)
        if(*iter) delete *iter;

    if (pNOTDocIterator_)
        delete pNOTDocIterator_;

    if (pDocIteratorQueue_)
        delete pDocIteratorQueue_;
}

void ORDocumentIterator::initDocIteratorQueue()
{
    if (docIteratorList_.size() < 1)
        return;
    pDocIteratorQueue_ = new DocumentIteratorQueue(docIteratorList_.size());
    DocumentIterator* pDocIterator;
    vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
    while (iter != docIteratorList_.end())
    {
        pDocIterator = (*iter);
        if (pDocIterator)
        {
            pDocIterator->setCurrent(false);
            if(pDocIterator->next())
                pDocIteratorQueue_->insert(pDocIterator);
            else
            {
                ///If a DocumentIterator does not contain member, remove it from docIteratorList_
                *iter = NULL;
                delete pDocIterator;
            }
        }
        iter ++;
    }
}

void ORDocumentIterator::add(DocumentIterator* pDocIterator)
{
    if (pDocIterator->isNot())
    {
        hasNot_ = true;
        if (NULL == pNOTDocIterator_)
            pNOTDocIterator_ = new NOTDocumentIterator();
        pNOTDocIterator_->add(pDocIterator);
    }
    else
        docIteratorList_.push_back(pDocIterator);
}

void ORDocumentIterator::add(VirtualPropertyTermDocumentIterator* pDocIterator)
{
    docIteratorList_.push_back(pDocIterator);
    std::sort( docIteratorList_.begin(), docIteratorList_.end() );
    docIteratorList_.erase( std::unique( docIteratorList_.begin(), docIteratorList_.end() ), docIteratorList_.end() );
}

bool ORDocumentIterator::next()
{
    if (!hasNot_)
        return do_next();

    if (! initNOTIterator_)
    {
        initNOTIterator_ = true;
        if (pNOTDocIterator_->next())
            currDocOfNOTIter_ = pNOTDocIterator_->doc();
        else
            currDocOfNOTIter_ = MAX_DOC_ID;
    }

    bool ret = do_next();

    if (currDoc_ > currDocOfNOTIter_)
        currDocOfNOTIter_ = pNOTDocIterator_->skipTo(currDoc_);

    if (currDoc_ == currDocOfNOTIter_)
        return move_together_with_not();

    assert(currDoc_ < currDocOfNOTIter_);
    return ret;
}

bool ORDocumentIterator::move_together_with_not()
{
    bool ret;
    do
    {
        ret = do_next();
        if (pNOTDocIterator_->next())
            currDocOfNOTIter_ = pNOTDocIterator_->doc();
        else
            currDocOfNOTIter_ = MAX_DOC_ID;
    }
    while (ret&&(currDoc_ == currDocOfNOTIter_));

    return ret;
}

bool ORDocumentIterator::do_next()
{
    if (pDocIteratorQueue_ == NULL)
    {
        initDocIteratorQueue();

        if (pDocIteratorQueue_ == NULL)
            return false;

        DocumentIterator* top = pDocIteratorQueue_->top();
        if (top == NULL)
            return false;

        currDoc_ = top->doc();

        for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
        {
            DocumentIterator* pEntry = pDocIteratorQueue_->getAt(i);
            if (currDoc_ == pEntry->doc())
                pEntry->setCurrent(true);
            else
                pEntry->setCurrent(false);
        }
        return true;
    }

    DocumentIterator* top = pDocIteratorQueue_->top();

    while (top != NULL && top->isCurrent())
    {
        top->setCurrent(false);
        if (top->next())
            pDocIteratorQueue_->adjustTop();
        else pDocIteratorQueue_->pop();
        top = pDocIteratorQueue_->top();
    }

    if (top == NULL)
        return false;

    currDoc_ = top->doc();

    ///we can not use priority queue here because if some dociterator
    ///is removed from that queue, we should set flag for it.
    for (std::vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
            iter != docIteratorList_.end(); ++iter)
    {
        DocumentIterator* pEntry = (*iter);
        if(pEntry)
        {
            if (currDoc_ == pEntry->doc())
                pEntry->setCurrent(true);
            else
                pEntry->setCurrent(false);
        }
    }

    return true;
}

#if SKIP_ENABLED
docid_t ORDocumentIterator::skipTo(docid_t target)
{
    if (!hasNot_)
        return do_skipTo(target);
    else
    {
        docid_t nFoundId, currentDoc = target;
        do
        {
            nFoundId = do_skipTo(currentDoc);
            currDocOfNOTIter_ = pNOTDocIterator_->skipTo(currentDoc);
            if((nFoundId != MAX_DOC_ID) && ((nFoundId == currentDoc) &&(currDocOfNOTIter_ == currentDoc)))
                return MAX_DOC_ID;
            currentDoc = nFoundId;
        }
        while ((nFoundId != MAX_DOC_ID)&&(nFoundId == currDocOfNOTIter_));
        return nFoundId;
    }
}

docid_t ORDocumentIterator::do_skipTo(docid_t target)
{
    if(pDocIteratorQueue_ == NULL)
    {
        initDocIteratorQueue();
        if (pDocIteratorQueue_ == NULL)
        {
            currDoc_ = MAX_DOC_ID;
            return MAX_DOC_ID;
        }
    }

    if (pDocIteratorQueue_->size() < 1)
    {
        currDoc_ = MAX_DOC_ID;
        return MAX_DOC_ID;
    }
    docid_t nFoundId = MAX_DOC_ID;
    do
    {
        DocumentIterator* top = pDocIteratorQueue_->top();
        currDoc_ = top->doc();

        std::vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
        for (; iter != docIteratorList_.end(); ++iter)
        {
            if (*iter)
            {
                if((*iter)->doc() == currDoc_)
                    (*iter)->setCurrent(true);
                else
                    (*iter)->setCurrent(false);
            }
        }

        if (currDoc_ >= target)
        {
            if(pDocIteratorQueue_->size() < 1)
            {
                currDoc_ = MAX_DOC_ID;
                return MAX_DOC_ID;
            }
            else
            {
                return currDoc_;
            }
        }
        else
        {
            nFoundId = top->skipTo(target);

            if((MAX_DOC_ID == nFoundId)||(nFoundId < target))
            {
                pDocIteratorQueue_->pop();
                if (pDocIteratorQueue_->size() < 1)
                {
                    currDoc_ = MAX_DOC_ID;
                    return MAX_DOC_ID;
                }
            }
            else
            {
                pDocIteratorQueue_->adjustTop();
            }
        }
    }
    while (true);

}
#endif

void ORDocumentIterator::doc_item(
    RankDocumentProperty& rankDocumentProperty,
    unsigned propIndex)
{
    DocumentIterator* pEntry;
    for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    {
        pEntry = pDocIteratorQueue_->getAt(i);
        if (pEntry->isCurrent())
            pEntry->doc_item(rankDocumentProperty,propIndex);
    }
}

void ORDocumentIterator::df_cmtf(
    DocumentFrequencyInProperties& dfmap,
    CollectionTermFrequencyInProperties& ctfmap,
    MaxTermFrequencyInProperties& maxtfmap)
{
    DocumentIterator* pEntry;
    std::vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
    for (; iter != docIteratorList_.end(); ++iter)
    {
        pEntry = (*iter);
        if(pEntry)
            pEntry->df_cmtf(dfmap, ctfmap, maxtfmap);
    }
}

void ORDocumentIterator:: setUB(bool useOriginalQuery, UpperBoundInProperties& ubmap)
{
    std::vector<DocumentIterator*>::iterator it = docIteratorList_.begin();
    for (; it != docIteratorList_.end(); it++)
    {
        (*it)->setUB(useOriginalQuery, ubmap);
    }

    unsigned short nItems = docIteratorList_.size();
    missRate_ = (missRate_ - nItems) / missRate_;
}

float ORDocumentIterator::getUB()
{
    float minUB = std::numeric_limits<float>::max();
    std::vector<DocumentIterator*>::iterator it = docIteratorList_.begin();
    for (; it != docIteratorList_.end(); it++)
    {
        if (!*it)
            continue;
        float ub = (*it)->getUB();
        if (ub < minUB )
            minUB = ub;
    }
    return minUB / (1 - missRate_);
}

count_t ORDocumentIterator::tf()
{
    DocumentIterator* pEntry;
    count_t maxtf = 0;
    count_t tf=0;
    for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    {
        pEntry = pDocIteratorQueue_->getAt(i);
        if (pEntry->isCurrent())
        {
            tf = pEntry->tf();
            if (tf > maxtf)
                maxtf = tf;
        }
    }

    return maxtf;
}

void ORDocumentIterator::queryBoosting(
    double& score,
    double& weight)
{
    DocumentIterator* pEntry;
    for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    {
        pEntry = pDocIteratorQueue_->getAt(i);
        if (pEntry->isCurrent())
        {
            pEntry->queryBoosting(score, weight);
        }
    }
}

void ORDocumentIterator::print(int level)
{
    cout << std::string(level*4, ' ') << "|--[ "<< "ORIter current: " << current_<<" "<< currDoc_ << " ]"<< endl;

    DocumentIterator* pEntry;
    for (size_t i = 0; i < docIteratorList_.size(); ++i)
    {
        pEntry = docIteratorList_[i];
        if (pEntry)
            pEntry->print(level+1);
    }
}


{
    DocumentIterator* pEntry;
    count_t maxtf = 0;
    count_t tf=0;
    for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    {
        pEntry = pDocIteratorQueue_->getAt(i);
        if (pEntry->isCurrent())
        {
            tf = pEntry->tf();
            if (tf > maxtf)
                maxtf = tf;
        }
    }

    return maxtf;
}

#include "ORDocumentIterator.h"
#include "NOTDocumentIterator.h"
#include "VirtualPropertyTermDocumentIterator.h"

#include <algorithm>
#include <limits>

using namespace std;
using namespace sf1r;

ORDocumentIterator::ORDocumentIterator()
    :pDocIteratorQueue_(NULL)
    ,hasNot_(false)
    ,currDocOfNOTIter_(MAX_DOC_ID)
    ,initNOTIterator_(false)
    ,pNOTDocIterator_(NULL)
{
}

ORDocumentIterator::~ORDocumentIterator()
{
    vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
    for (; iter != docIteratorList_.end(); ++iter)
        if(*iter) delete *iter;

    if (pNOTDocIterator_)
        delete pNOTDocIterator_;

    if (pDocIteratorQueue_)
        delete pDocIteratorQueue_;
}

void ORDocumentIterator::initDocIteratorQueue()
{
    if (docIteratorList_.size() < 1)
        return;
    pDocIteratorQueue_ = new DocumentIteratorQueue(docIteratorList_.size());
    DocumentIterator* pDocIterator;
    vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
    while (iter != docIteratorList_.end())
    {
        pDocIterator = (*iter);
        if (pDocIterator)
        {
            pDocIterator->setCurrent(false);
            if(pDocIterator->next())
                pDocIteratorQueue_->insert(pDocIterator);
            else
            {
                ///If a DocumentIterator does not contain member, remove it from docIteratorList_
                *iter = NULL;
                delete pDocIterator;
            }
        }
        iter ++;
    }
}

void ORDocumentIterator::add(DocumentIterator* pDocIterator)
{
    if (pDocIterator->isNot())
    {
        hasNot_ = true;
        if (NULL == pNOTDocIterator_)
            pNOTDocIterator_ = new NOTDocumentIterator();
        pNOTDocIterator_->add(pDocIterator);
    }
    else
        docIteratorList_.push_back(pDocIterator);
}

void ORDocumentIterator::add(VirtualPropertyTermDocumentIterator* pDocIterator)
{
    docIteratorList_.push_back(pDocIterator);
    std::sort( docIteratorList_.begin(), docIteratorList_.end() );
    docIteratorList_.erase( std::unique( docIteratorList_.begin(), docIteratorList_.end() ), docIteratorList_.end() );
}

bool ORDocumentIterator::next()
{
    if (!hasNot_)
        return do_next();

    if (! initNOTIterator_)
    {
        initNOTIterator_ = true;
        if (pNOTDocIterator_->next())
            currDocOfNOTIter_ = pNOTDocIterator_->doc();
        else
            currDocOfNOTIter_ = MAX_DOC_ID;
    }

    bool ret = do_next();

    if (currDoc_ > currDocOfNOTIter_)
        currDocOfNOTIter_ = pNOTDocIterator_->skipTo(currDoc_);

    if (currDoc_ == currDocOfNOTIter_)
        return move_together_with_not();

    assert(currDoc_ < currDocOfNOTIter_);
    return ret;
}

bool ORDocumentIterator::move_together_with_not()
{
    bool ret;
    do
    {
        ret = do_next();
        if (pNOTDocIterator_->next())
            currDocOfNOTIter_ = pNOTDocIterator_->doc();
        else
            currDocOfNOTIter_ = MAX_DOC_ID;
    }
    while (ret&&(currDoc_ == currDocOfNOTIter_));

    return ret;
}

bool ORDocumentIterator::do_next()
{
    if (pDocIteratorQueue_ == NULL)
    {
        initDocIteratorQueue();

        if (pDocIteratorQueue_ == NULL)
            return false;

        DocumentIterator* top = pDocIteratorQueue_->top();
        if (top == NULL)
            return false;

        currDoc_ = top->doc();

        for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
        {
            DocumentIterator* pEntry = pDocIteratorQueue_->getAt(i);
            if (currDoc_ == pEntry->doc())
                pEntry->setCurrent(true);
            else
                pEntry->setCurrent(false);
        }
        return true;
    }

    DocumentIterator* top = pDocIteratorQueue_->top();

    while (top != NULL && top->isCurrent())
    {
        top->setCurrent(false);
        if (top->next())
            pDocIteratorQueue_->adjustTop();
        else pDocIteratorQueue_->pop();
        top = pDocIteratorQueue_->top();
    }

    if (top == NULL)
        return false;

    currDoc_ = top->doc();

    ///we can not use priority queue here because if some dociterator
    ///is removed from that queue, we should set flag for it.
    for (std::vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
            iter != docIteratorList_.end(); ++iter)
    {
        DocumentIterator* pEntry = (*iter);
        if(pEntry)
        {
            if (currDoc_ == pEntry->doc())
                pEntry->setCurrent(true);
            else
                pEntry->setCurrent(false);
        }
    }

    return true;
}

#if SKIP_ENABLED
docid_t ORDocumentIterator::skipTo(docid_t target)
{
    if (!hasNot_)
        return do_skipTo(target);
    else
    {
        docid_t nFoundId, currentDoc = target;
        do
        {
            nFoundId = do_skipTo(currentDoc);
            currDocOfNOTIter_ = pNOTDocIterator_->skipTo(currentDoc);
            if((nFoundId != MAX_DOC_ID) && ((nFoundId == currentDoc) &&(currDocOfNOTIter_ == currentDoc)))
                return MAX_DOC_ID;
            currentDoc = nFoundId;
        }
        while ((nFoundId != MAX_DOC_ID)&&(nFoundId == currDocOfNOTIter_));
        return nFoundId;
    }
}

docid_t ORDocumentIterator::do_skipTo(docid_t target)
{
    if(pDocIteratorQueue_ == NULL)
    {
        initDocIteratorQueue();
        if (pDocIteratorQueue_ == NULL)
        {
            currDoc_ = MAX_DOC_ID;
            return MAX_DOC_ID;
        }
    }

    if (pDocIteratorQueue_->size() < 1)
    {
        currDoc_ = MAX_DOC_ID;
        return MAX_DOC_ID;
    }
    docid_t nFoundId = MAX_DOC_ID;
    do
    {
        DocumentIterator* top = pDocIteratorQueue_->top();
        currDoc_ = top->doc();

        std::vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
        for (; iter != docIteratorList_.end(); ++iter)
        {
            if (*iter)
            {
                if((*iter)->doc() == currDoc_)
                    (*iter)->setCurrent(true);
                else
                    (*iter)->setCurrent(false);
            }
        }

        if (currDoc_ >= target)
        {
            if(pDocIteratorQueue_->size() < 1)
            {
                currDoc_ = MAX_DOC_ID;
                return MAX_DOC_ID;
            }
            else
            {
                return currDoc_;
            }
        }
        else
        {
            nFoundId = top->skipTo(target);

            if((MAX_DOC_ID == nFoundId)||(nFoundId < target))
            {
                pDocIteratorQueue_->pop();
                if (pDocIteratorQueue_->size() < 1)
                {
                    currDoc_ = MAX_DOC_ID;
                    return MAX_DOC_ID;
                }
            }
            else
            {
                pDocIteratorQueue_->adjustTop();
            }
        }
    }
    while (true);

}
#endif

void ORDocumentIterator::doc_item(
    RankDocumentProperty& rankDocumentProperty,
    unsigned propIndex)
{
    DocumentIterator* pEntry;
    for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    {
        pEntry = pDocIteratorQueue_->getAt(i);
        if (pEntry->isCurrent())
            pEntry->doc_item(rankDocumentProperty,propIndex);
    }
}

void ORDocumentIterator::df_cmtf(
    DocumentFrequencyInProperties& dfmap,
    CollectionTermFrequencyInProperties& ctfmap,
    MaxTermFrequencyInProperties& maxtfmap)
{
    DocumentIterator* pEntry;
    std::vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
    for (; iter != docIteratorList_.end(); ++iter)
    {
        pEntry = (*iter);
        if(pEntry)
            pEntry->df_cmtf(dfmap, ctfmap, maxtfmap);
    }
}

void ORDocumentIterator:: setUB(bool useOriginalQuery, UpperBoundInProperties& ubmap)
{
    std::vector<DocumentIterator*>::iterator it = docIteratorList_.begin();
    for (; it != docIteratorList_.end(); it++)
    {
        (*it)->setUB(useOriginalQuery, ubmap);
    }

    unsigned short nItems = docIteratorList_.size();
    missRate_ = (missRate_ - nItems) / missRate_;
}

float ORDocumentIterator::getUB()
{
    float minUB = std::numeric_limits<float>::max();
    std::vector<DocumentIterator*>::iterator it = docIteratorList_.begin();
    for (; it != docIteratorList_.end(); it++)
    {
        if (!*it)
            continue;
        float ub = (*it)->getUB();
        if (ub < minUB )
            minUB = ub;
    }
    return minUB / (1 - missRate_);
}

count_t ORDocumentIterator::tf()

void ORDocumentIterator::queryBoosting(
    double& score,
    double& weight)
{
    DocumentIterator* pEntry;
    for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    {
        pEntry = pDocIteratorQueue_->getAt(i);
        if (pEntry->isCurrent())
        {
            pEntry->queryBoosting(score, weight);
        }
    }
}

void ORDocumentIterator::print(int level)
{
    cout << std::string(level*4, ' ') << "|--[ "<< "ORIter current: " << current_<<" "<< currDoc_ << " ]"<< endl;

    DocumentIterator* pEntry;
    for (size_t i = 0; i < docIteratorList_.size(); ++i)
    {
        pEntry = docIteratorList_[i];
        if (pEntry)
            pEntry->print(level+1);
    }
}