package org.teachingkidsprogramming.recipes.completed.section08events;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;

import org.teachingextensions.logo.Tortoise;
import org.teachingextensions.logo.utils.ColorUtils.PenColors;

//***********************ANSWER: In Progress***************************//
//      Need to write English comments and copy to STUDENT section     //
//
public class TortoiseMaze
{
  public static void main(String[] args)
  {
    new TortoiseMaze();
  }
  public TortoiseMaze()
  {
    setUpTortoise();
    // add image icons
    ImageIcon leftArrow = new ImageIcon(
        "../TeachingKidsProgramming.Source.Java/src/main/resources/icons/arrow-left.png");
    ImageIcon upArrow = new ImageIcon(
        "../TeachingKidsProgramming.Source.Java/src/main/resources/icons/arrow-up.png");
    ImageIcon downArrow = new ImageIcon(
        "../TeachingKidsProgramming.Source.Java/src/main/resources/icons/arrow-down.png");
    ImageIcon rightArrow = new ImageIcon(
        "../TeachingKidsProgramming.Source.Java/src/main/resources/icons/arrow-right.png");
    // add buttons using icons
    JButton leftButton = new JButton("left", leftArrow);
    JButton upButton = new JButton("forward", upArrow);
    JButton downButton = new JButton("back", downArrow);
    JButton rightButton = new JButton("right", rightArrow);
    // add button(s) to your window
    addButtonToWindow(leftButton);
    addButtonToWindow(upButton);
    addButtonToWindow(downButton);
    addButtonToWindow(rightButton);
    // add action(s) to your buttons
    rightButton.addActionListener(new ActionListener()
    {
      @Override
      public void actionPerformed(ActionEvent e)
      {
        Tortoise.turn(90);
      }
    });
    leftButton.addActionListener(new ActionListener()
    {
      @Override
      public void actionPerformed(ActionEvent e)
      {
        Tortoise.turn(-90);
      }
    });
    upButton.addActionListener(new ActionListener()
    {
      @Override
      public void actionPerformed(ActionEvent e)
      {
        Tortoise.move(35);
      }
    });
    downButton.addActionListener(new ActionListener()
    {
      @Override
      public void actionPerformed(ActionEvent e)
      {
        Tortoise.move(-35);
      }
    });
    Tortoise.setVisible(true);
  }
  /*  setup code */
  private void setUpTortoise()
  {
    Tortoise.show();
    Tortoise.setSpeed(10);
    Tortoise.setPenColor(PenColors.Greens.Green);
    Tortoise.setPenWidth(4);
    // TODO: Generate a unique maze png and set as background for this maze instance
    //call tortoiseMaze.setupBackground
  }
  private void addButtonToWindow(JButton button)
  {
    Tortoise.getBackgroundWindow().addButton(button);
  }
}


package org.teachingextensions.logo.utils.TKPLogoUtils;

import org.teachingextensions.logo.Tortoise;
import org.teachingextensions.logo.utils.ColorUtils.ColorWheel;
import org.teachingextensions.logo.utils.ColorUtils.PenColors;
import org.teachingkidsprogramming.recipes.completed.section01forloops.MakeALogo;

/**
 *
 * The TKPLogo allows you to create a super cool TKP logo on your window
 */
public class TKPLogo
{
  /**
   * Sets up a particular set of Colors on the Color Wheel
   *
Example: {@code TKPLogo.setupColorWheel();}

   */
  public static void setupColorWheel()
  {
    ColorWheel.addColor(PenColors.Grays.Gray);
    ColorWheel.addColor(PenColors.Greens.Green);
    ColorWheel.addColor(PenColors.Pinks.Pink);
    ColorWheel.addColor(PenColors.Purples.Purple);
    ColorWheel.addColor(PenColors.Blues.Blue);
    ColorWheel.addColor(PenColors.Yellows.Yellow);
    ColorWheel.addColor(PenColors.Browns.Brown);
    ColorWheel.addColor(PenColors.Oranges.Orange);
    ColorWheel.addColor(PenColors.Reds.Red);
    ColorWheel.addColor(PenColors.Whites.White);
    setupBackgroundAndLines();
  }
  private static void setupBackgroundAndLines()
  {
    Tortoise.getBackgroundWindow().setBackground(ColorWheel.getRandomColorFromWheel());
    Tortoise.setPenWidth(4);
  }
  /**
   * Draws an amazing</> TKP inner P
   *
Example: {@code TKPLogo.draw_inner_tkp_P();}

   */
  public static void draw_inner_tkp_P()
  {
    Tortoise.setX(MakeALogo.XValue + 355);
    Tortoise.setY(MakeALogo.YValue - 135);
    Tortoise.turn(180);
    Tortoise.move(10);
    TKPLogo.curve6();
    Tortoise.move(10);
    Tortoise.turn(90);
    Tortoise.move(50);
    Tortoise.hide();
    Tortoise.turn(1);
  }
  /**
   * Draws an awesome</> TKP outer P
   *
Example: {@code TKPLogo.draw_outer_tkp_P();}

   */
  public static void draw_outer_tkp_P()
  {
    Tortoise.setAngle(180);
    Tortoise.setX(MakeALogo.XValue + 320);
    Tortoise.setY(MakeALogo.YValue);
    Tortoise.turn(180);
    Tortoise.move(15);
    Tortoise.turn(80);
    Tortoise.move(10);
    Tortoise.turn(-80);
    Tortoise.move(120);
    Tortoise.turn(-80);
    Tortoise.move(10);
    Tortoise.turn(80);
    Tortoise.move(15);
    Tortoise.turn(90);
    Tortoise.move(47);
    TKPLogo.curve5();
    Tortoise.move(12);
    Tortoise.turn(-90);
    Tortoise.move(50);
    Tortoise.turn(-80);
    Tortoise.move(10);
    Tortoise.turn(80);
    Tortoise.move(15);
    Tortoise.turn(90);
    Tortoise.move(43);
  }
  /**
   * Draws an outstanding</> TKP right bracket
   *
Example: {@code TKPLogo.drawRightBracket();}

   */
  public static void drawRightBracket()
  {
    Tortoise.setAngle(-90);
    Tortoise.setX(MakeALogo.XValue + 250);
    Tortoise.setY(MakeALogo.YValue - 20);
    Tortoise.turn(180);
    Tortoise.move(30);
    TKPLogo.curve3();
    Tortoise.move(40);
    TKPLogo.curve4();
    Tortoise.move(10);
    Tortoise.turn(-90);
    Tortoise.move(10);
    Tortoise.turn(-90);
    Tortoise.move(10);
    TKPLogo.curve4();
    Tortoise.move(40);
    TKPLogo.curve3();
    Tortoise.move(30);
    Tortoise.turn(-90);
    Tortoise.move(10);
    Tortoise.turn(-90);
    Tortoise.move(15);
    TKPLogo.curve1();
    Tortoise.move(35);
    TKPLogo.curve2();
    Tortoise.turn(180);
    TKPLogo.curve2();
    Tortoise.move(35);
    TKPLogo.curve1();
    Tortoise.move(15);
    Tortoise.turn(-90);
    Tortoise.move(11);
  }
  /**
   * Draws an original</> TKP left bracket
   *
Example: {@code TKPLogo.drawLeftBracket();}

   */
  public static void drawLeftBracket()
  {
    Tortoise.setAngle(-90);
    Tortoise.setX(MakeALogo.XValue + 130);
    Tortoise.setY(MakeALogo.YValue - 20);
    Tortoise.move(30);
    TKPLogo.curve1();
    Tortoise.move(40);
    TKPLogo.curve2();
    Tortoise.move(10);
    Tortoise.turn(90);
    Tortoise.move(10);
    Tortoise.turn(90);
    Tortoise.move(10);
    TKPLogo.curve2();
    Tortoise.move(40);
    TKPLogo.curve1();
    Tortoise.move(30);
    Tortoise.turn(90);
    Tortoise.move(10);
    Tortoise.turn(90);
    Tortoise.move(15);
    TKPLogo.curve3();
    Tortoise.move(35);
    TKPLogo.curve4();
    Tortoise.turn(180);
    TKPLogo.curve4();
    Tortoise.move(35);
    TKPLogo.curve3();
    Tortoise.move(15);
    Tortoise.turn(90);
    Tortoise.move(10);
  }
  /**
   * Draws an incredible</> TKP T
   *
Example: {@code TKPLogo.draw_tkp_T();}

   */
  public static void draw_tkp_T()
  {
    Tortoise.setX(MakeALogo.XValue);
    Tortoise.setY(MakeALogo.YValue);
    Tortoise.move(15);
    Tortoise.turn(80);
    Tortoise.move(10);
    Tortoise.turn(-80);
    Tortoise.move(120);
    Tortoise.turn(-90);
    Tortoise.move(15);
    Tortoise.turn(-75);
    Tortoise.move(10);
    Tortoise.turn(75);
    Tortoise.move(15);
    Tortoise.turn(90);
    Tortoise.move(35);
    Tortoise.turn(90);
    Tortoise.move(95);
    Tortoise.turn(90);
    Tortoise.move(35);
    Tortoise.turn(90);
    Tortoise.move(15);
    Tortoise.turn(75);
    Tortoise.move(10);
    Tortoise.turn(-75);
    Tortoise.move(15);
    Tortoise.turn(-90);
    Tortoise.move(120);
    Tortoise.turn(-80);
    Tortoise.move(10);
    Tortoise.turn(80);
    Tortoise.move(15);
    Tortoise.turn(90);
    Tortoise.move(50);
  }
  /**
   * Draws an impressive</> TKP K
   *
Example: {@code TKPLogo.draw_tkp_K();}

   */
  public static void draw_tkp_K()
  {
    Tortoise.setAngle(180);
    Tortoise.setX(MakeALogo.XValue + 150);
    Tortoise.setY(MakeALogo.YValue + 15);
    Tortoise.turn(180);
    Tortoise.move(200);
    Tortoise.turn(90);
    Tortoise.move(30);
    Tortoise.turn(90);
    Tortoise.move(128);
    Tortoise.turn(-150);
    Tortoise.move(70);
    Tortoise.turn(90);
    Tortoise.move(30);
    Tortoise.turn(90);
    Tortoise.move(70);
    Tortoise.turn(-80);
    Tortoise.move(80);
    Tortoise.turn(140);
    Tortoise.move(40);
    Tortoise.turn(40);
    Tortoise.move(60);
    Tortoise.turn(-130);
    Tortoise.move(45);
    Tortoise.turn(90);
    Tortoise.move(30);
    Tortoise.turn(2);
  }
  private static void curve6()
  {
    for (int i = 0; i < 180; i++)
    {
      double size = 0.43;
      Tortoise.turn(1);
      Tortoise.move(size);
    }
  }
  private static void curve5()
  {
    for (int i = 0; i < 180; i++)
    {
      double size = 0.75;
      Tortoise.turn(1);
      Tortoise.move(size);
      Tortoise.move(-size);
      Tortoise.move(size);
    }
  }
  private static void curve4()
  {
    for (int i = 0; i < 90; i++)
    {
      double size = 0.15;
      Tortoise.turn(1);
      Tortoise.move(size);
    }
  }
  private static void curve2()
  {
    for (int i = 0; i < 90; i++)
    {
      double size = 0.15;
      Tortoise.turn(-1);
      Tortoise.move(size);
    }
  }
  private static void curve1()
  {
    for (int i = 0; i < 90; i++)
    {
      double size = 0.25;
      Tortoise.turn(1);
      Tortoise.move(size);
    }
  }
  private static void curve3()
  {
    for (int i = 0; i < 90; i++)
    {
      double size = 0.25;
      Tortoise.turn(-1);
      Tortoise.move(size);
    }
  }
}


package org.teachingextensions.WindowUtils;

import java.util.ArrayList;
import java.util.List;

import org.teachingextensions.logo.Turtle;
import org.teachingextensions.logo.utils.ColorUtils.PenColors;
import org.teachingextensions.logo.utils.InterfaceUtils.MultiTurtlePainter;
import org.teachingextensions.logo.utils.InterfaceUtils.MultiTurtleTrailPainter;
import org.teachingextensions.logo.utils.InterfaceUtils.TurtleFrame;
import org.teachingextensions.logo.utils.LineAndShapeUtils.Paintable;

/**
 * Use this window when you want to put more than one turtle on the same window
 */
public class MultiTurtleWindow extends TurtleWindow
{
  private List<Turtle> turtles = new ArrayList<Turtle>();
  public MultiTurtleWindow()
  {
    super("Turtles, Turtles, Turtles!");
    this.setBackground(PenColors.Blues.DarkSlateBlue);
  }
  /**
   * Adds a turtle instance to a window
   * NOTE: this method must be called BEFORE calling any other methods on turtle instances
   *
Example: {@code multiTurtleWindow.addTurtle(myTurtle)}

   *
   * @param turtle
   *     A turtle instance
   */
  public void addTurtle(Turtle turtle)
  {
    if (turtle == null) { return; }
    turtle.setFrame(this.getFrame());
    turtle.setPanel(this);
    this.turtles.add(turtle);
    clearPainters();
    configurePainters();
  }
  @Override
  public TurtleWindow init(Turtle turtle, TurtleFrame frame)
  {
    return this;
  }
  @Override
  protected Paintable createTurtleTrailPainter()
  {
    this.setTrailPainter(new MultiTurtleTrailPainter(this.turtles));
    return this.getTrailPainter();
  }
  @Override
  protected Paintable createTurtlePainter()
  {
    this.setTurtlePainter(new MultiTurtlePainter(this.turtles, this.getImage()));
    return this.getTurtlePainter();
  }
  /**
   * Gets a count of turtles for a window
   *
Example: {@code multiTurtleWindow.getTurtlesCount()}

   *
   */
  public int getTurtleCount()
  {
    return this.turtles.size();
  }
  /**
   * Adds a turtle instance to a window and shows it on the window
   *
Example: {@code multiTurtleWindow.addAndShowTurtle(myTurtle)}

   *
   * @param turtle
   *     A turtle instance
   */
  public void addAndShowTurtle(Turtle turtle)
  {
    this.addTurtle(turtle);
    this.showTurtle(turtle);
  }
  private void showTurtle(Turtle turtle)
  {
    turtle.show();
  }
}


package org.teachingkidsprogramming.recipes.completed.section04mastery;

import org.teachingextensions.logo.Tortoise;
import org.teachingextensions.logo.utils.ColorUtils.ColorWheel;
import org.teachingextensions.logo.utils.ColorUtils.PenColors;

public class PentagonCrazy
{
  public static void main(String[] args)
  {
    Tortoise.show();
    //    Make the tortoise move as fast as possible --#3
    Tortoise.setSpeed(10);
    //    CreateColorPalette (recipe below) --#8
    createColorPalette();
    //    DrawPentagon (recipe below) --#10
    drawPentagon();
  }
  //    ------------- Recipe for CreateColorPalette (HINT: Use PenColors) --#8
  private static void createColorPalette()
  {
    //     Add steel blue to the color wheel --#7
    ColorWheel.addColor(PenColors.Blues.SteelBlue);
    //     Add dark orchid to the color wheel --#11
    ColorWheel.addColor(PenColors.Purples.DarkOrchid);
    //     Add dark slate blue to the color wheel --#12
    ColorWheel.addColor(PenColors.Blues.DarkSlateBlue);
    //     Add teal to the color wheel --#13
    ColorWheel.addColor(PenColors.Blues.Teal);
    //     Add indigo to the color wheel --#14
    ColorWheel.addColor(PenColors.Purples.Indigo);
  }
  //    ------------- End of CreateColorPalette recipe
  //    ------------- Recipe for AdjustPen --#9
  private static void adjustPen()
  {
    //     Change the color of the line the tortoise draws to the next color on the color wheel --#6
    Tortoise.setPenColor(ColorWheel.getNextColor());
    //     Increase the tortoises pen width by 1 --#15
    Tortoise.setPenWidth(Tortoise.getPenWidth() + 1.0);
    //     If the tortoise's pen width is greater than 4, then --#17
    if (Tortoise.getPenWidth() > 4)
    {
      //     Reset the pen width to 1 --#16
      Tortoise.setPenWidth(1);
    }
  }
  //    ------------- End of AdjustPen recipe
  //    ------------- Recipe for DrawPentagon --#10
  private static void drawPentagon()
  {
    //    Do the following 200 times --#2
    for (int i = 0; i < 200; i++)
    {
      //     AdjustPen (recipe below) --#9
      adjustPen();
      //     Move the tortoise the length of a side --#4
      Tortoise.move(i);
      //     Turn the tortoise 1/5th of 360 degrees --#1
      Tortoise.turn(360.0 / 5);
      //     Turn the tortoise 1 more degree --#5
      Tortoise.turn(1);
    }
  }
  //    ------------- End of DrawPentagon recipe
}


package org.teachingextensions.logo;

import java.awt.Color;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;

import org.teachingextensions.WindowUtils.ProgramWindow;
import org.teachingextensions.WindowUtils.TurtleWindow;
import org.teachingextensions.approvals.lite.util.ThreadLauncher;
import org.teachingextensions.approvals.lite.util.lambda.Action0;
import org.teachingextensions.approvals.lite.util.persistence.Saver;
import org.teachingextensions.approvals.lite.util.persistence.SavingException;
import org.teachingextensions.logo.utils.AngleCalculator;
import org.teachingextensions.logo.utils.DeltaCalculator;
import org.teachingextensions.logo.utils.InterfaceUtils.TurtleFrame;
import org.teachingextensions.logo.utils.LineAndShapeUtils.LineSegment;

/**
 *
 * The Turtle allows you to draw lines and shapes by moving it around on the window, and you can put more than one turtle on the same window...
 */
public class Turtle
{
  public static final int     TEST_SPEED      = Integer.MIN_VALUE;
  private static final double MAX_MOVE_AMOUNT = 5.0;
  private String              DEFAULT_NAME    = "Grace Hopper";
  public TurtleWindow         panel           = new TurtleWindow();
  public List<LineSegment>    trail           = new ArrayList<LineSegment>();
  private double              x               = 640 / 2;
  private double              y               = 480 / 2;
  private double              angleInDegrees  = 0;
  private TurtleFrame         frame           = new TurtleFrame();
  private int                 speed           = 1;
  private Color               color           = Color.black;
  private int                 width           = 2;
  private boolean             penDown         = true;
  private boolean             hidden;
  private Animals             animal;
  private Sound               sound           = new Sound();
  private String              name            = DEFAULT_NAME;
  public BufferedImage getImage()
  {
    BufferedImage image = panel.getWindowImage();
    clear();
    return image;
  }
  public void clear()
  {
    trail.clear();
    if (panel != null)
    {
      panel.getCanvas().clear();
    }
  }
  public void setPanel(TurtleWindow panel)
  {
    this.panel = panel;
  }
  public int getX()
  {
    return (int) x;
  }
  public void setX(Number x)
  {
    this.x = x.doubleValue();
  }
  public int getY()
  {
    return (int) y;
  }
  public void setY(Number y)
  {
    this.y = y.doubleValue();
  }
  public double getAngleInDegrees()
  {
    return angleInDegrees;
  }
  public void setAngleInDegrees(double angleInDegrees)
  {
    this.angleInDegrees = angleInDegrees;
  }
  public void turn(double amount)
  {
    double max = getTurnAmount(amount);
    Saver<Double> s = new Turner();
    animate(amount, max, s);
  }
  private double getTurnAmount(double amount)
  {
    amount = Math.abs(amount);
    if (getSpeed() == TEST_SPEED) { return amount; }
    return amount / (11 - getSpeed());
  }
  private void animate(double amount, double max, Saver<Double> s)
  {
    double sign = amount > 0 ? 1 : -1;
    amount = Math.abs(amount);
    while (amount > max)
    {
      s.save(max * sign);
      refreshPanel();
      amount -= max;
    }
    s.save(amount * sign);
    refreshPanel();
  }
  private void refreshPanel()
  {
    refreshPanel(panel);
  }
  private void refreshPanel(ProgramWindow panel)
  {
    long delay = getDelay();
    if (delay != TEST_SPEED)
    {
      panel.repaint();
      try
      {
        Thread.sleep(delay);
      }
      catch (InterruptedException e)
      {
        // do nothing
      }
    }
  }
  private long getDelay()
  {
    if (getSpeed() == 10) { return 1; }
    if (getSpeed() == TEST_SPEED) { return TEST_SPEED; }
    return 100 / getSpeed();
  }
  public String getName()
  {
    return name;
  }
  /**
   * Sets the name for a turtle instance
   *
Example: {@code myTurtle.setName(name)}

   *
   * @param name
   *     Your turtle's name
   */
  public void setName(String name)
  {
    this.name = name;
  }
  public int getSpeed()
  {
    return speed;
  }
  /**
   * Sets the speed that a turtle instance moves
   *
Example: {@code myTurtle.setSpeed(speed)}

   *
   * @param speed
   *     The speed from 1 (slowest) to 10 (fastest)
   */
  public void setSpeed(int speed)
  {
    if (speed != TEST_SPEED)
    {
      if (speed < 1 || 10 < speed) { throw new RuntimeException(String.format(
          "I call shenanigans!!!\nThe speed '%s' is not between the acceptable range of [1-10]\nPerhaps you should read the documentation",
          speed)); }
    }
    this.speed = speed;
  }
  public double getHeadingInDegrees()
  {
    return angleInDegrees;
  }
  /**
   * Sets the distance that a turtle instance moves in pixels
   *
Example: {@code myTurtle.move(100)}

   *
   * @param amount
   *     The distance that your turtle moves in pixels. Negative numbers will move your turtle backwards
   */
  public void move(Number amount)
  {
    double max = MAX_MOVE_AMOUNT;
    Saver<Double> s = penDown ? new Mover(new Point(getX(), getY())) : new EmptyMover();
    animate(amount.doubleValue(), max, s);
  }
  private void moveWithoutAnimation(Double save)
  {
    DeltaCalculator calculator = new DeltaCalculator(this.angleInDegrees, save);
    x += calculator.getX();
    y += calculator.getY();
  }
  public LineSegment[] getTrail()
  {
    return trail.toArray(new LineSegment[0]);
  }
  public Color getPenColor()
  {
    return color;
  }
  public void setPenColor(Color color)
  {
    this.color = color;
  }
  public int getPenWidth()
  {
    return width;
  }
  public void setPenWidth(int width)
  {
    this.width = width;
  }
  public void show()
  {
    this.panel.init(this, this.frame);
    hidden = false;
    this.setFrameVisible(true);
    this.setPanelVisible(true);
    refreshPanel(panel);
  }
  public TurtleWindow getBackgroundWindow()
  {
    return panel;
  }
  /**
   * Sets the animal
   *
Example: {@code myTurtle.setAnimal(Animals.spider)}

   *
   * @param animal
   *     The type of animal that appears on your window
   */
  public void setAnimal(Animals animal)
  {
    refreshPanel();
    getBackgroundWindow().setAnimal(animal);
    this.animal = animal;
  }
  public void penUp()
  {
    penDown = false;
  }
  public void penDown()
  {
    penDown = true;
  }
  public void print(String string)
  {
    // TODO Auto-generated method stub
  }
  public void speak()
  {
    this.sound.playSound();
  }
  public void hide()
  {
    hidden = true;
  }
  public boolean isHidden()
  {
    return hidden;
  }
  public void moveTo(final int x, final int y)
  {
    ThreadLauncher.launch(new Action0()
    {
      @Override
      public void call()
      {
        moveSynchronized(x, y);
      }
    });
  }
  public void moveSynchronized(int x, int y)
  {
    AngleCalculator calculator = new AngleCalculator(getX(), getY(), x, y);
    double angleOfWherePointIs = calculator.getDegreesWith0North();
    double direction = angleOfWherePointIs - getAngleInDegrees();
    turn(direction);
    // move the turtle the distance to the x y point
    double distance = new Point(x, y).distance(getX(), getY());
    move(distance);
  }
  /**
   * Draws a triangle of a specified size and orientation
   *
Example: {@code myTurtle.drawTriangle(size)}

   *
   * @param size
   *     The size of a side of the triangle, negative numbers draw an upside down triangle
   */
  public void drawTriangle(int size)
  {
    for (int i = 1; i <= 3; i++)
    {
      this.turn(360 / 3);
      this.move(size);
    }
  }
  /**
   * Draws a star of a specified size
   *
Example: {@code myTurtle.drawStar(size)}

   *
   * @param size
   *     The size of a side of the star
   */
  public void drawStar(int size)
  {
    for (int i = 1; i <= 5; i++)
    {
      this.turn(360 / 2.5);
      this.move(size);
    }
  }
  public boolean isDead()
  {
    return this.animal == Animals.ExplodedTurtle;
  }
  /**
   * Draws a lightning bolt of a specified length
   *
Example: {@code myTurtle.drawLightning(length)}

   *
   * @param length
   *     The length of a lightning bolt
   */
  public void drawLightning(int length)
  {
    this.setX(50);
    this.setY(350);
    this.setSpeed(10);
    for (int i = 1; i < 5; i++)
    {
      this.setPenWidth(i * 4);
      this.turn(65 + i);
      this.move(length);
      this.turn(-65);
      this.move(length);
    }
  }
  public void setFrameVisible(boolean b)
  {
    this.frame.setVisible(b);
  }
  public void setPanelVisible(boolean b)
  {
    panel.setVisible(b);
  }
  public void setFrame(JFrame frame2)
  {
    this.frame = new TurtleFrame(frame2);
  }
  public void setSound(Sound sound)
  {
    this.sound = sound;
  }
  /**
   * Current types are: ExplodedTurtle, Turtle, Spider, Squid, Unicorn
   */
  public enum Animals {
                       ExplodedTurtle, Turtle, Spider, Squid, Unicorn
  }
  private class Turner implements Saver<Double>
  {
    @Override
    public Double save(Double save) throws SavingException
    {
      smallTurn(save);
      return save;
    }
    private void smallTurn(double i)
    {
      angleInDegrees += i;
    }
  }
  private class Mover implements Saver<Double>
  {
    private final Point starting;
    private LineSegment line = null;
    public Mover(Point point)
    {
      this.starting = point;
    }
    @Override
    public Double save(Double save) throws SavingException
    {
      moveWithoutAnimation(save);
      if (line != null)
      {
        trail.remove(line);
      }
      line = new LineSegment(color, starting, new Point(getX(), getY()), width);
      trail.add(line);
      return save;
    }
  }
  private class EmptyMover implements Saver<Double>
  {
    @Override
    public Double save(Double save) throws SavingException
    {
      moveWithoutAnimation(save);
      return save;
    }
  }
}


package org.teachingextensions.logo.utils.LineAndShapeUtils;

import java.awt.Color;
import java.awt.Graphics2D;

import javax.swing.JPanel;

import org.teachingextensions.WindowUtils.ProgramWindow;
import org.teachingextensions.logo.utils.ColorUtils.PenColors;

/**
 * The Diamond allows you to draw diamonds on the window
 */
public class Diamond implements Paintable
{
  private final int   radius;
  private final Color mainColor;
  private int         x;
  private int         y;
  private int         percentTransparent;
  public Diamond(int radius, Color color)
  {
    this.radius = radius;
    this.mainColor = color;
  }
  /**
   * Sets the corners of the diamond
   *
Example: {@code  diamond.setCorners(8,10)}

   *
   * @param x
   *          The x value
   * @param y
   *          The y value
   */
  public void setCorners(int x, int y)
  {
    this.x = x;
    this.y = y;
  }
  public int getRadius()
  {
    return this.radius;
  }
  /**
   * Adds a diamond to the window
   *
Example: {@code  diamond.addTo(panel)}

   *
   * @param panel
   *          the ProgramWindow or panel
   */
  public void addTo(ProgramWindow panel)
  {
    panel.getCanvas().add(this);
  }
  /**
   * Paints a diamond
   *
Example: {@code  diamond.paint(g,caller)}

   *
   * @param g
   *          the graphics object
   * @param caller
   *          the Program Window or panel
   */
  @Override
  public void paint(Graphics2D g, JPanel caller)
  {
    Color color2 = PenColors.getTransparentVersion(mainColor, percentTransparent);
    g.setColor(color2);
    int width = 400;
    int height = 300;
    g.rotate(50);
    g.fillRect(x, y, width, height);
  }
  /**
   * Sets the transparency of the diamond
   *
Example: {@code  diamond.setTransparency(80)}

   *
   * @param percentTransparent
   *          The percentage of transparency of the diamond
   */
  public void setTransparency(int percentTransparent)
  {
    this.percentTransparent = percentTransparent;
  }
  public void removeFrom(ProgramWindow panel)
  {
    panel.remove(this);
  }
  public int getX()
  {
    return this.x;
  }
  public int getY()
  {
    return this.y;
  }
}


package org.teachingkidsprogramming.recipes.completed.section05recursion;

import org.teachingextensions.logo.Tortoise;
import org.teachingextensions.logo.Turtle.Animals;
import org.teachingextensions.logo.utils.ColorUtils.PenColors;

public class SpiderWeb
{
  public static void main(String[] args)
  {
    Tortoise.show();
    //    Make the tortoise go as fast as possible --#6
    Tortoise.setSpeed(10);
    //    Change the width of the line the tortoise draws to 1 pixel --#12
    Tortoise.setPenWidth(1);
    //    Change the Tortoise to a Spider --#14
    Tortoise.setAnimal(Animals.Spider);
    //    Change the pen color of the line the tortoise draws to red --#13.1
    Tortoise.setPenColor(PenColors.Reds.Red);
    //    Set the color of the background window to black (HINT: use the Tortoise to get the background window) --#13.2
    Tortoise.getBackgroundWindow().setBackground(PenColors.Grays.Black);
    //    The current length of a line is 10 pixels --#1.2
    double length = 10.5;
    //    The current zoom is 1.1 --#8.2
    double zoom = 1.1;
    //    Do the following 10 times --#10.1
    for (int i = 0; i < 10; i++)
    {
      //     WeaveOneLayer (recipe below) --#9
      length = weaveOneLayer(length, zoom);
      //     Change the zoom so it is multiplied by 1.3 --#11
      zoom *= 1.3;
      //    End Repeat
    }
  }
  //    ------------- Recipe for WeaveOneLayer --#9
  public static double weaveOneLayer(double length, double zoom)
  {
    //    Do the following 6 times --#5
    for (int i = 0; i < 6; i++)
    {
      //     DrawTriangle (recipe below) --#4.2
      drawTriangle(length);
      //     Turn the tortoise 1/6th of 360 degrees to the right --#7
      Tortoise.turn(360.0 / 6);
      //     Increase the length of the line by the current zoom --#8.1
      length += zoom;
      //    End Repeat --#10.2
    }
    return length;
  }
  //    ------------- End of WeaveOneLayer recipe --#9
  //    ------------- Recipe for DrawTriangle --#4
  public static void drawTriangle(double length)
  {
    //    Do the following 3 times --#3.1
    for (int i = 0; i < 3; i++)
    {
      //     Move the tortoise the length of a line --#1.1
      Tortoise.move(length);
      //     Turn the tortoise 1/3rd of 360 degrees --#2
      Tortoise.turn(360.0 / 3);
      //    End Repeat --#3.2
    }
  }
  //    ------------- End of DrawTriangle recipe --#4
}


package org.teachingextensions.logo.utils.MazeUtils;

/******************************************************************************
 *  Compilation:  javac StdRandom.java
 *  Execution:    java StdRandom
 *  Dependencies: StdOut.java
 *
 *  A library of static methods to generate pseudo-random numbers from
 *  different distributions (bernoulli, uniform, gaussian, discrete,
 *  and exponential). Also includes a method for shuffling an array.
 *
 *
 *  %  java StdRandom 5
 *  seed = 1316600602069
 *  59 16.81826  true 8.83954  0
 *  32 91.32098  true 9.11026  0
 *  35 10.11874  true 8.95396  3
 *  92 32.88401  true 8.87089  0
 *  72 92.55791  true 9.46241  0
 *
 *  % java StdRandom 5
 *  seed = 1316600616575
 *  96 60.17070  true 8.72821  0
 *  79 32.01607  true 8.58159  0
 *  81 59.49065  true 9.10423  1
 *  96 51.65818  true 9.02102  0
 *  99 17.55771  true 8.99762  0
 *
 *  % java StdRandom 5 1316600616575
 *  seed = 1316600616575
 *  96 60.17070  true 8.72821  0
 *  79 32.01607  true 8.58159  0
 *  81 59.49065  true 9.10423  1
 *  96 51.65818  true 9.02102  0
 *  99 17.55771  true 8.99762  0
 *
 *
 *  Remark
 *  ------
 *    - Relies on randomness of nextDouble() method in java.util.Random
 *      to generate pseudorandom numbers in [0, 1).
 *
 *    - This library allows you to set and get the pseudorandom number seed.
 *
 *    - See http://www.honeylocust.com/RngPack/ for an industrial
 *      strength random number generator in Java.
 *
 ******************************************************************************/
import java.util.Random;

/**
 *  The {@code StdRandom} class provides static methods for generating
 *  random number from various discrete and continuous distributions,
 *  including Bernoulli, uniform, Gaussian, exponential, pareto,
 *  Poisson, and Cauchy. It also provides method for shuffling an
 *  array or subarray.
 *

 *  For additional documentation,
 *  see Section 2.2 of
 *  Introduction to Programming in Java: An Interdisciplinary Approach
 *  by Robert Sedgewick and Kevin Wayne.
 *
 *  @author Robert Sedgewick
 *  @author Kevin Wayne
 */
public final class StdRandom
{
  private static Random random; // pseudo-random number generator
  private static long   seed;  // pseudo-random number generator seed
  // static initializer
  static
  {
    // this is how the seed was set in Java 1.4
    seed = System.currentTimeMillis();
    random = new Random(seed);
  }
  // don't instantiate
  private StdRandom()
  {
  }
  /**
   * Sets the seed of the pseudorandom number generator.
   * This method enables you to produce the same sequence of "random"
   * number for each execution of the program.
   * Ordinarily, you should call this method at most once per program.
   *
   * @param s the seed
   */
  public static void setSeed(long s)
  {
    seed = s;
    random = new Random(seed);
  }
  /**
   * Returns the seed of the pseudorandom number generator.
   *
   * @return the seed
   */
  public static long getSeed()
  {
    return seed;
  }
  /**
   * Returns a random real number uniformly in [0, 1).
   *
   * @return a random real number uniformly in [0, 1)
   */
  public static double uniform()
  {
    return random.nextDouble();
  }
  /**
   * Returns a random integer uniformly in [0, n).
   *
   * @param n number of possible integers
   * @return a random integer uniformly between 0 (inclusive) and <tt>N</tt> (exclusive)
   * @throws IllegalArgumentException if <tt>n <= 0</tt>
   */
  public static int uniform(int n)
  {
    if (n <= 0)
      throw new IllegalArgumentException("Parameter N must be positive");
    return random.nextInt(n);
  }
  ///////////////////////////////////////////////////////////////////////////
  //  STATIC METHODS BELOW RELY ON JAVA.UTIL.RANDOM ONLY INDIRECTLY VIA
  //  THE STATIC METHODS ABOVE.
  ///////////////////////////////////////////////////////////////////////////
  /**
   * Returns a random real number uniformly in [0, 1).
   *
   * @return     a random real number uniformly in [0, 1)
   * @deprecated Replaced by {@link #uniform()}.
   */
  @Deprecated
  public static double random()
  {
    return uniform();
  }
  /**
   * Returns a random integer uniformly in [a, b).
   *
   * @param  a the left endpoint
   * @param  b the right endpoint
   * @return a random integer uniformly in [a, b)
   * @throws IllegalArgumentException if <tt>b <= a</tt>
   * @throws IllegalArgumentException if <tt>b - a >= Integer.MAX_VALUE</tt>
   */
  public static int uniform(int a, int b)
  {
    if (b <= a)
      throw new IllegalArgumentException("Invalid range");
    if ((long) b - a >= Integer.MAX_VALUE)
      throw new IllegalArgumentException("Invalid range");
    return a + uniform(b - a);
  }
  /**
   * Returns a random real number uniformly in [a, b).
   *
   * @param  a the left endpoint
   * @param  b the right endpoint
   * @return a random real number uniformly in [a, b)
   * @throws IllegalArgumentException unless <tt>a < b</tt>
   */
  public static double uniform(double a, double b)
  {
    if (!(a < b))
      throw new IllegalArgumentException("Invalid range");
    return a + uniform() * (b - a);
  }
  /**
   * Returns a random boolean from a Bernoulli distribution with success
   * probability p.
   *
   * @param  p the probability of returning <tt>true</tt>
   * @return <tt>true</tt> with probability <tt>p</tt> and
   *         <tt>false</tt> with probability <tt>p</tt>
   * @throws IllegalArgumentException unless <tt>p >= 0.0</tt> and <tt>p <= 1.0</tt>
   */
  public static boolean bernoulli(double p)
  {
    if (!(p >= 0.0 && p <= 1.0))
      throw new IllegalArgumentException("Probability must be between 0.0 and 1.0");
    return uniform() < p;
  }
  /**
   * Returns a random boolean from a Bernoulli distribution with success
   * probability 1/2.
   *
   * @return <tt>true</tt> with probability 1/2 and
   *         <tt>false</tt> with probability 1/2
   */
  public static boolean bernoulli()
  {
    return bernoulli(0.5);
  }
  /**
   * Returns a random real number from a standard Gaussian distribution.
   *
   * @return a random real number from a standard Gaussian distribution
   *         (mean 0 and standard deviation 1).
   */
  public static double gaussian()
  {
    // use the polar form of the Box-Muller transform
    double r, x, y;
    do
    {
      x = uniform(-1.0, 1.0);
      y = uniform(-1.0, 1.0);
      r = x * x + y * y;
    }
    while (r >= 1 || r == 0);
    return x * Math.sqrt(-2 * Math.log(r) / r);
    // Remark:  y * Math.sqrt(-2 * Math.log(r) / r)
    // is an independent random gaussian
  }
  /**
   * Returns a random real number from a Gaussian distribution with mean μ
   * and standard deviation σ.
   *
   * @param  mu the mean
   * @param  sigma the standard deviation
   * @return a real number distributed according to the Gaussian distribution
   *         with mean <tt>mu</tt> and standard deviation <tt>sigma</tt>
   */
  public static double gaussian(double mu, double sigma)
  {
    return mu + sigma * gaussian();
  }
  /**
   * Returns a random integer from a geometric distribution with success
   * probability p.
   *
   * @param  p the parameter of the geometric distribution
   * @return a random integer from a geometric distribution with success
   *         probability <tt>p</tt>
   * @throws IllegalArgumentException unless <tt>p >= 0.0</tt> and <tt>p <= 1.0</tt>
   */
  public static int geometric(double p)
  {
    if (!(p >= 0.0 && p <= 1.0))
      throw new IllegalArgumentException("Probability must be between 0.0 and 1.0");
    // using algorithm given by Knuth
    return (int) Math.ceil(Math.log(uniform()) / Math.log(1.0 - p));
  }
  /**
   * Returns a random integer from a Poisson distribution with mean λ.
   *
   * @param  lambda the mean of the Poisson distribution
   * @return a random integer from a Poisson distribution with mean <tt>lambda</tt>
   * @throws IllegalArgumentException unless <tt>lambda > 0.0</tt> and not infinite
   */
  public static int poisson(double lambda)
  {
    if (!(lambda > 0.0))
      throw new IllegalArgumentException("Parameter lambda must be positive");
    if (Double.isInfinite(lambda))
      throw new IllegalArgumentException("Parameter lambda must not be infinite");
    // using algorithm given by Knuth
    // see http://en.wikipedia.org/wiki/Poisson_distribution
    int k = 0;
    double p = 1.0;
    double L = Math.exp(-lambda);
    do
    {
      k++;
      p *= uniform();
    }
    while (p >= L);
    return k - 1;
  }
  /**
   * Returns a random real number from the standard Pareto distribution.
   *
   * @return a random real number from the standard Pareto distribution
   */
  public static double pareto()
  {
    return pareto(1.0);
  }
  /**
   * Returns a random real number from a Pareto distribution with
   * shape parameter α.
   *
   * @param  alpha shape parameter
   * @return a random real number from a Pareto distribution with shape
   *         parameter <tt>alpha</tt>
   * @throws IllegalArgumentException unless <tt>alpha > 0.0</tt>
   */
  public static double pareto(double alpha)
  {
    if (!(alpha > 0.0))
      throw new IllegalArgumentException("Shape parameter alpha must be positive");
    return Math.pow(1 - uniform(), -1.0 / alpha) - 1.0;
  }
  /**
   * Returns a random real number from the Cauchy distribution.
   *
   * @return a random real number from the Cauchy distribution.
   */
  public static double cauchy()
  {
    return Math.tan(Math.PI * (uniform() - 0.5));
  }
  /**
   * Returns a random integer from the specified discrete distribution.
   *
   * @param  a the probability of occurrence of each integer
   * @return a random integer from a discrete distribution:
   *         <tt>i</tt> with probability <tt>a[i]</tt>
   * @throws NullPointerException if <tt>a</tt> is <tt>null</tt>
   * @throws IllegalArgumentException if sum of array entries is not (very nearly) equal to <tt>1.0</tt>
   * @throws IllegalArgumentException unless <tt>a[i] >= 0.0</tt> for each index <tt>i</tt>
   */
  public static int discrete(double[] a)
  {
    if (a == null)
      throw new NullPointerException("argument array is null");
    double EPSILON = 1E-14;
    double sum = 0.0;
    for (int i = 0; i = 0.0))
        throw new IllegalArgumentException("array entry " + i + " must be nonnegative: " + a[i]);
      sum = sum + a[i];
    }
    if (sum > 1.0 + EPSILON || sum < 1.0 - EPSILON)
      throw new IllegalArgumentException("sum of array entries does not approximately equal 1.0: " + sum);
    // the for loop may not return a value when both r is (nearly) 1.0 and when the
    // cumulative sum is less than 1.0 (as a result of floating-point roundoff error)
    while (true)
    {
      double r = uniform();
      sum = 0.0;
      for (int i = 0; i  r)
          return i;
      }
    }
  }
  /**
   * Returns a random real number from an exponential distribution
   * with rate λ.
   *
   * @param  lambda the rate of the exponential distribution
   * @return a random real number from an exponential distribution with
   *         rate <tt>lambda</tt>
   * @throws IllegalArgumentException unless <tt>lambda > 0.0</tt>
   */
  public static double exp(double lambda)
  {
    if (!(lambda > 0.0))
      throw new IllegalArgumentException("Rate lambda must be positive");
    return -Math.log(1 - uniform()) / lambda;
  }
  /**
   * Rearranges the elements of the specified array in uniformly random order.
   *
   * @param  a the array to shuffle
   * @throws NullPointerException if <tt>a</tt> is <tt>null</tt>
   */
  public static void shuffle(Object[] a)
  {
    if (a == null)
      throw new NullPointerException("argument array is null");
    int N = a.length;
    for (int i = 0; i < N; i++)
    {
      int r = i + uniform(N - i); // between i and N-1
      Object temp = a[i];
      a[i] = a[r];
      a[r] = temp;
    }
  }
  /**
   * Rearranges the elements of the specified array in uniformly random order.
   *
   * @param  a the array to shuffle
   * @throws NullPointerException if <tt>a</tt> is <tt>null</tt>
   */
  public static void shuffle(double[] a)
  {
    if (a == null)
      throw new NullPointerException("argument array is null");
    int N = a.length;
    for (int i = 0; i < N; i++)
    {
      int r = i + uniform(N - i); // between i and N-1
      double temp = a[i];
      a[i] = a[r];
      a[r] = temp;
    }
  }
  /**
   * Rearranges the elements of the specified array in uniformly random order.
   *
   * @param  a the array to shuffle
   * @throws NullPointerException if <tt>a</tt> is <tt>null</tt>
   */
  public static void shuffle(int[] a)
  {
    if (a == null)
      throw new NullPointerException("argument array is null");
    int N = a.length;
    for (int i = 0; i < N; i++)
    {
      int r = i + uniform(N - i); // between i and N-1
      int temp = a[i];
      a[i] = a[r];
      a[r] = temp;
    }
  }
  /**
   * Rearranges the elements of the specified subarray in uniformly random order.
   *
   * @param  a the array to shuffle
   * @param  lo the left endpoint (inclusive)
   * @param  hi the right endpoint (inclusive)
   * @throws NullPointerException if <tt>a</tt> is <tt>null</tt>
   * @throws IndexOutOfBoundsException unless <tt>(0 <= lo) && (lo <= hi) && (hi < a.length)</tt>
   *
   */
  public static void shuffle(Object[] a, int lo, int hi)
  {
    if (a == null)
      throw new NullPointerException("argument array is null");
    if (lo < 0 || lo > hi || hi >= a.length) { throw new IndexOutOfBoundsException("Illegal subarray range"); }
    for (int i = lo; i <= hi; i++)
    {
      int r = i + uniform(hi - i + 1); // between i and hi
      Object temp = a[i];
      a[i] = a[r];
      a[r] = temp;
    }
  }
  /**
   * Rearranges the elements of the specified subarray in uniformly random order.
   *
   * @param  a the array to shuffle
   * @param  lo the left endpoint (inclusive)
   * @param  hi the right endpoint (inclusive)
   * @throws NullPointerException if <tt>a</tt> is <tt>null</tt>
   * @throws IndexOutOfBoundsException unless <tt>(0 <= lo) && (lo <= hi) && (hi < a.length)</tt>
   */
  public static void shuffle(double[] a, int lo, int hi)
  {
    if (a == null)
      throw new NullPointerException("argument array is null");
    if (lo < 0 || lo > hi || hi >= a.length) { throw new IndexOutOfBoundsException("Illegal subarray range"); }
    for (int i = lo; i <= hi; i++)
    {
      int r = i + uniform(hi - i + 1); // between i and hi
      double temp = a[i];
      a[i] = a[r];
      a[r] = temp;
    }
  }
  /**
   * Rearranges the elements of the specified subarray in uniformly random order.
   *
   * @param  a the array to shuffle
   * @param  lo the left endpoint (inclusive)
   * @param  hi the right endpoint (inclusive)
   * @throws NullPointerException if <tt>a</tt> is <tt>null</tt>
   * @throws IndexOutOfBoundsException unless <tt>(0 <= lo) && (lo <= hi) && (hi < a.length)</tt>
   */
  public static void shuffle(int[] a, int lo, int hi)
  {
    if (a == null)
      throw new NullPointerException("argument array is null");
    if (lo < 0 || lo > hi || hi >= a.length) { throw new IndexOutOfBoundsException("Illegal subarray range"); }
    for (int i = lo; i <= hi; i++)
    {
      int r = i + uniform(hi - i + 1); // between i and hi
      int temp = a[i];
      a[i] = a[r];
      a[r] = temp;
    }
  }
  /**
   * Unit test.
   */
  public static void main(String[] args)
  {
    int N = Integer.parseInt(args[0]);
    if (args.length == 2)
      StdRandom.setSeed(Long.parseLong(args[1]));
    double[] t = {.5, .3, .1, .1};
    StdOut.println("seed = " + StdRandom.getSeed());
    for (int i = 0; i < N; i++)
    {
      StdOut.printf("%2d ", uniform(100));
      StdOut.printf("%8.5f ", uniform(10.0, 99.0));
      StdOut.printf("%5b ", bernoulli(.5));
      StdOut.printf("%7.5f ", gaussian(9.0, .2));
      StdOut.printf("%2d ", discrete(t));
      StdOut.println();
    }
    String[] a = "A B C D E F G".split(" ");
    for (String s : a)
      StdOut.print(s + " ");
    StdOut.println();
  }
}


package io.robe.assets.http;

import com.google.common.net.HttpHeaders;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

/**
 * Http Asset. Caching is supported with remote files lastModified and expires headers. Etag forwarded automaticly.
 */
public class HttpAsset {
    private boolean cached;
    private URL asset;
    private byte[] cache;
    private long lastModified;
    private long expireAt;
    private String ETAG;

    /**
     * Creates and http entry
     *
     * @param path   http path
     * @param cached to cache or not to cache.
     */
    public HttpAsset(String path, boolean cached) {
        setAsset(path);
        this.cached = cached;
        loadAsset();
    }

    /**
     * Sets http http according to path.
     * It must exist as http.
     *
     * @param path
     */
    public void setAsset(String path) {
        try {
            this.asset = new URL(path);
        } catch (MalformedURLException e) {
            e.printStackTrace();
            throw new RuntimeException("URL does not exist: " + path);

        }

    }

    /**
     * Loads http data. If cache is enabled checks modification date and loads to cache.
     * Else just returns http
     *
     * @return
     */
    public byte[] loadAsset() {
        if (!cached) {
            return loadAssetFromURL();
        } else if (System.currentTimeMillis() >= expireAt)
            loadAssetToCache();
        return cache;

    }

    /**
     * Loads http from the http
     *
     * @return
     */
    private byte[] loadAssetFromURL() {
        try {
            URLConnection cnn = this.asset.openConnection();
            cnn.connect();
            int b = -1;
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            while ((b = cnn.getInputStream().read()) != -1)
                stream.write(b);
            stream.flush();
            stream.close();

            this.lastModified = cnn.getLastModified();
            this.expireAt = cnn.getExpiration();
            this.ETAG = cnn.getHeaderField(HttpHeaders.ETAG);

            return stream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * Writes http to a cache (byte array)
     */
    private void loadAssetToCache() {
        try {
            cache = loadAssetFromURL();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    public long getLastModified() {
        return lastModified;
    }

    public String getETAG() {
        return ETAG;
    }
}


package io.robe.common.utils;

/**
 * Provides frequently needed methods for string operations.
 */
public final class Strings {

    private Strings() {
    }

    /**
     * Capitalizes the first character of the word given.
     * It will convert i to I
     *
     * @param word
     * @return result
     */
    public static final String capitalizeFirstChar(String word) {
        return Character.toUpperCase(word.charAt(0)) + word.substring(1);
    }

    /**
     * Un capitalizes the first character of the word given.
     * It will convert i to I
     *
     * @param word
     * @return result
     */
    public static final String unCapitalizeFirstChar(String word) {
        return Character.toLowerCase(word.charAt(0)) + word.substring(1);
    }
}


package io.robe.admin.resources;

import io.dropwizard.hibernate.UnitOfWork;
import io.dropwizard.jersey.PATCH;
import io.robe.admin.hibernate.dao.UserDao;
import io.robe.admin.hibernate.entity.User;
import io.robe.auth.AbstractAuthResource;
import io.robe.auth.Credentials;
import io.robe.auth.RobeAuth;
import io.robe.common.service.RobeService;
import io.robe.common.service.search.SearchParam;
import io.robe.common.service.search.model.SearchModel;
import io.robe.common.utils.reflection.Fields;
import org.hibernate.CacheMode;
import org.hibernate.FlushMode;

import javax.inject.Inject;
import javax.validation.Valid;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;

@Path("users")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class UserResource extends AbstractAuthResource<User> {

    private UserDao userDao;

    @Inject
    public UserResource(UserDao userDao) {
        super(userDao);
        this.userDao = userDao;
    }

    /**
     * Returns all {@link User}s as a collection.
     *
     * @param credentials injected by {@link RobeAuth} annotation for authentication.
     * @return all {@link User}s as a collection with.
     */

    @RobeService(group = "User", description = "Returns all Users as a collection.")
    @GET
    @UnitOfWork(readOnly = true, cacheMode = CacheMode.GET, flushMode = FlushMode.MANUAL)
    public List<User> getAll(@RobeAuth Credentials credentials, @SearchParam SearchModel search) {
        return userDao.findAllStrict(search);
    }

    /**
     * Returns a single User matches with the given id.
     *

     * Status Code:
     * Not Found  404
     *
     * @param credentials injected by {@link RobeAuth} annotation for authentication.
     * @param id          This is the oid of {@link User}
     * @return a {@link User} resource matches with the given id.
     */
    @RobeService(group = "User", description = "Returns a User resource matches with the given id.")
    @Path("{id}")
    @GET
    @UnitOfWork(readOnly = true, cacheMode = CacheMode.GET, flushMode = FlushMode.MANUAL)
    public User get(@RobeAuth Credentials credentials, @PathParam("id") String id) {
        User entity = userDao.findById(id);
        if (entity == null) {
            throw new WebApplicationException(Response.status(404).build());
        }
        return entity;
    }

    /**
     * Create as a {@link User} resource.
     *
     * @param credentials injected by {@link RobeAuth} annotation for authentication.
     * @param model       data of {@link User}
     * @return Create as a {@link User} resource.
     */
    @RobeService(group = "User", description = "Create as a User resource.")
    @POST
    @UnitOfWork
    public User create(@RobeAuth Credentials credentials, @Valid User model) {
        return userDao.create(model);
    }

    /**
     * Updates a single {@link User} matches with the given id.
     *

     * Status Code:
     * Not Found  404
     * Not Matches 412
     *
     * @param credentials injected by {@link RobeAuth} annotation for authentication.
     * @param id          This is the oid of {@link User}
     * @param model       data of {@link User}
     * @return Updates a single {@link User} matches with the given id.
     */
    @RobeService(group = "User", description = "Updates a single User matches with the given id.")
    @PUT
    @UnitOfWork
    @Path("{id}")
    public User update(@RobeAuth Credentials credentials, @PathParam("id") String id, @Valid User model) {

        if (!id.equals(model.getOid())) {
            throw new WebApplicationException(Response.status(412).build());
        }
        User entity = userDao.findById(id);
        if (entity == null) {
            throw new WebApplicationException(Response.status(404).build());
        }
        userDao.detach(entity);
        return userDao.update(model);
    }

    /**
     * Updates a single {@link User} matches with the given id.
     *

     * Status Code:
     * Not Found  404
     * Not Matches 412
     *
     * @param credentials injected by {@link RobeAuth} annotation for authentication.
     * @param id          This is the oid of {@link User}
     * @param model       data of {@link User}
     * @return Updates a single {@link User} matches with the given id.
     */
    @RobeService(group = "User", description = "Updates a single User matches with the given id.")
    @PATCH
    @UnitOfWork
    @Path("{id}")
    public User merge(@RobeAuth Credentials credentials, @PathParam("id") String id, User model) {
        if (!id.equals(model.getOid()))
            throw new WebApplicationException(Response.status(412).build());
        User dest = userDao.findById(id);
        if (dest == null) {
            throw new WebApplicationException(Response.status(404).build());
        }
        Fields.mergeRight(model, dest);
        return userDao.update(dest);
    }

    /**
     * Deletes a single {@link User} matches with the given id.
     *

     * Status Code:
     * Not Found  404
     * Not Matches 412
     *
     * @param credentials injected by {@link RobeAuth} annotation for authentication.
     * @param id          This is the oid of {@link User}
     * @param model       data of {@link User}
     * @return delete a single {@link User} matches with the given id.
     */
    @RobeService(group = "User", description = "Deletes a single User matches with the given id.")
    @DELETE
    @UnitOfWork
    @Path("{id}")
    public User delete(@RobeAuth Credentials credentials, @PathParam("id") String id, @Valid User model) {
        if (!id.equals(model.getOid())) {
            throw new WebApplicationException(Response.status(412).build());
        }
        User entity = userDao.findById(id);
        if (entity == null) {
            throw new WebApplicationException(Response.status(404).build());
        }
        return userDao.delete(entity);
    }

}


package io.robe.hibernate.dao;

import com.google.common.base.Preconditions;
import io.dropwizard.hibernate.AbstractDAO;
import io.robe.common.service.headers.ResponseHeadersUtil;
import io.robe.common.service.search.model.SearchModel;
import io.robe.common.utils.TypeReference;
import io.robe.hibernate.RobeHibernateBundle;
import io.robe.hibernate.criteria.api.Transformer;
import io.robe.hibernate.entity.RobeEntity;
import io.robe.hibernate.criteria.api.Criteria;
import io.robe.hibernate.criteria.api.Result;
import io.robe.hibernate.criteria.query.Query;
import io.robe.hibernate.criteria.hql.TransformerImpl;
import org.hibernate.SessionFactory;

import javax.inject.Inject;
import java.io.Serializable;
import java.util.*;

/**
 * Basic Dao Class which limits {@link io.dropwizard.hibernate.AbstractDAO} to take
 * type parameters which extends {@link io.robe.hibernate.entity.BaseEntity}
 *
 * @param <T> Type of the entity parameter.
 */
public class BaseDao<T extends RobeEntity> extends AbstractDAO<T> {

    @Inject
    RobeHibernateBundle bundle;

    /**
     * Constructor with session factory injection by guice
     *
     * @param sessionFactory injected session factory
     */
    @Inject
    public BaseDao(SessionFactory sessionFactory) {
        super(sessionFactory);
    }

    /**
     * Returns modified list of the entities regarding to the search model.
     * {@inheritDoc}
     *
     * @return List of entities.
     */
    public Criteria<T> queryAllStrict(SearchModel search) {
        Query<T> query = new Query<>(new TransformerImpl<T>(this.currentSession()));
        return query.createCriteria(this.getEntityClass(), search);
    }

    /**
     * Returns modified list of the entities regarding to the search model.
     * {@inheritDoc}
     *
     * @return List of entities.
     */
    public Criteria<Map<String, Object>> queryAll(SearchModel search) {
        Transformer<Map<String, Object>> transformer = new TransformerImpl<>(this.currentSession(), Criteria.MAP_CLASS);
        Query<Map<String, Object>> query = new Query<>(transformer);
        return query.createCriteria(this.getEntityClass(), search);
    }

    /**
     * Returns modified list of the entities regarding to the search model.
     * {@inheritDoc}
     *
     * @return List of entities.
     */
    public <E> Criteria<E> queryAll(SearchModel search, Class<E> transformClass) {
        Query<E> query = new Query<>(new TransformerImpl<>(this.currentSession(), transformClass));
        return query.createCriteria(this.getEntityClass(), search);
    }

    /**
     * Returns modified list of the entities regarding to the search model.
     * {@inheritDoc}
     *
     * @return List of entities.
     */
    public List<T> findAllStrict(SearchModel search) {
        Result<T> resultPair = queryAllStrict(search).pairList();
        search.setTotalCount(resultPair.getTotalCount());
        ResponseHeadersUtil.addTotalCount(search);
        return resultPair.getList();
    }

    /**
     * Returns modified list of the entities regarding to the search model.
     * {@inheritDoc}
     *
     * @return List of entities.
     */
    public List<Map<String, Object>> findAll(SearchModel search) {
        Result<Map<String, Object>> resultPair = queryAll(search).pairList();
        search.setTotalCount(resultPair.getTotalCount());
        ResponseHeadersUtil.addTotalCount(search);
        return resultPair.getList();
    }

    /**
     * Returns modified list of the entities regarding to the search model.
     * {@inheritDoc}
     *
     * @return List of entities.
     */
    public <E> List<E> findAll(SearchModel search, Class<E> transformClass) {
        Result<E> resultPair = queryAll(search, transformClass).pairList();
        search.setTotalCount(resultPair.getTotalCount());
        ResponseHeadersUtil.addTotalCount(search);
        return resultPair.getList();
    }

    /**
     * {@inheritDoc}
     *
     * @return List of entities.
     */
    public List<T> findAllStrict() {
        return queryAllStrict(null).list();
    }

    /**
     * {@inheritDoc}
     *
     * @param oid id of the desired Entity
     * @return returns the result.
     */
    public T findById(Serializable oid) {
        return get(oid);
    }

    /**
     * {@inheritDoc}
     *
     * @param oid id of the Given Entity
     * @return returns the result.
     */
    @SuppressWarnings("unchecked")
    public T findById(Class<? extends RobeEntity> clazz, Serializable oid) {
        return (T) currentSession().get(clazz, Preconditions.checkNotNull(oid));
    }

    /**
     * Create a record for the given entity instance.
     *
     * @param entity to record.
     * @return updated version of the instance.
     */
    public T create(T entity) {
        return persist(entity);
    }

    /**
     * Update a record for the given entity instance.
     *
     * @param entity to record.
     * @return updated version of the instance.
     */
    public T update(T entity) {
        return persist(entity);
    }

    /**
     * Delete a record for the given entity instance.
     *
     * @param entity to record.
     * @return updated version of the instance.
     */
    public T delete(T entity) {
        currentSession().delete(entity);
        return entity;
    }

    /**
     * Flush the session.
     */
    public void flush() {
        currentSession().flush();
    }

    /**
     * Merges the entity with the session.
     *
     * @param entity entity to merge
     * @return
     */
    @SuppressWarnings("unchecked")
    public T merge(T entity) {
        return (T) currentSession().merge(entity);
    }

    /**
     * Detached the entity from session by evict method.
     *
     * @param entity entity to detach
     * @return
     */
    public T detach(T entity) {
        currentSession().evict(entity);
        return entity;
    }
}


package io.robe.assets.file;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.net.HttpHeaders;
import com.google.common.net.MediaType;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.Charset;

/**
 * Servlet for serving assets with configuration.
 * Cache mechanism holds only paths. Actual byte cache is managed by {@link io.robe.assets.file.FileAsset}
 *
 * @see io.dropwizard.servlets.assets.AssetServlet
 */

public class FileAssetServlet extends HttpServlet {

    private Cache<String, FileAsset> cache;
    private static final MediaType DEFAULT_MEDIA_TYPE = MediaType.HTML_UTF_8;

    private final String resourcePath;
    private final String uriPath;
    private final String indexFile;
    private final Charset defaultCharset;
    private final boolean cached;

    /**
     * Creates a new {@code FileAssetServlet} that serves static assets loaded from {@code resourceURL}
     *
     * @param resourcePath   the base URL from which assets are loaded
     * @param uriPath        the URI path fragment in which all requests are rooted
     * @param indexFile      the filename to use when directories are requested, or null to serve no
     *                       indexes
     * @param defaultCharset the default character set
     */
    public FileAssetServlet(String resourcePath,
                            String uriPath,
                            String indexFile,
                            Charset defaultCharset,
                            boolean cached) {
        this.resourcePath = fixPath(resourcePath);
        uriPath = uriPath.endsWith("/") ? uriPath.substring(0, uriPath.length() - 1) : uriPath;
        this.uriPath = uriPath.isEmpty() ? "/" : uriPath;
        this.indexFile = indexFile;
        this.defaultCharset = defaultCharset;
        this.cached = cached;
        cache = CacheBuilder.newBuilder().build();
    }

    /**
     * Helps to fix path
     *
     * @param path to fix
     * @return
     */
    private String fixPath(String path) {
        if (!path.isEmpty()) {
            if (!path.endsWith("/"))
                return path + '/';
            else
                return path;
        } else
            return path;
    }

    public String getIndexFile() {
        return indexFile;
    }

    @Override
    protected void doGet(HttpServletRequest req,
                         HttpServletResponse resp) throws ServletException, IOException {
        try {
            final StringBuilder builder = new StringBuilder(req.getServletPath());

            // If http is empty redirect to index http.

            if (req.getPathInfo() != null) {
                builder.append(req.getPathInfo());
            } else {
                builder.insert(0, req.getContextPath()).append("/");
                resp.sendRedirect(builder.toString());
                return;
            }

            String assetPath = builder.toString();
            //Get from cache if not available load it.
            FileAsset asset = cache.getIfPresent(assetPath);
            try{
                if (asset == null ) {
                    asset = loadAsset(assetPath);
                }}catch (RuntimeException e){

            }
            if (asset == null){
                if(!assetPath.contains(".")){
                    builder.delete(builder.lastIndexOf("/"),builder.length());
                    builder.append("/").append(getIndexFile());
                    asset = loadAsset(builder.toString());
                }

            }
            //If still it is null it means nothing to load.
            if (asset == null) {
                resp.sendError(HttpServletResponse.SC_NOT_FOUND);
                return;
            }

            // Maybe client got it already
            if (isDifferentFromClientCache(req, asset)) {
                resp.sendError(HttpServletResponse.SC_NOT_MODIFIED);
                return;
            }

            //Modify response identifiers
            resp.setDateHeader(HttpHeaders.LAST_MODIFIED, asset.getLastModified());
            resp.setHeader(HttpHeaders.ETAG, asset.getMd5());

            decideMimeAndEncoding(req, resp);

            try (ServletOutputStream output = resp.getOutputStream()) {
                output.write(asset.loadAsset());
            }
        } catch (RuntimeException e) {
            resp.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }

    private void decideMimeAndEncoding(HttpServletRequest req, HttpServletResponse resp) {
        //Decide mimetype
        String mime = req.getServletContext().getMimeType(req.getRequestURI());
        MediaType mediaType = (mime == null) ? DEFAULT_MEDIA_TYPE : MediaType.parse(mime);
        if (defaultCharset != null && mediaType.is(MediaType.ANY_TEXT_TYPE)) {
            mediaType = mediaType.withCharset(defaultCharset);
        }
        resp.setContentType(mediaType.type() + '/' + mediaType.subtype());
        if (mediaType.charset().isPresent()) {
            resp.setCharacterEncoding(mediaType.charset().get().toString());
        }
    }

    private FileAsset loadAsset(String path) {
        if (!path.startsWith(uriPath))
            return null;
        String absolutePath = path.substring(uriPath.length());
        absolutePath = absolutePath.startsWith("/") ? absolutePath.substring(1) : absolutePath;
        absolutePath = absolutePath.endsWith("/") ? absolutePath.substring(0, absolutePath.length() - 1) : absolutePath;
        absolutePath = this.resourcePath + absolutePath;

        FileAsset asset = new FileAsset(absolutePath, cached);
        cache.put(path, asset);

        return asset;
    }

    private long msToSec(long time) {
        return time / 1000;
    }

    private boolean isDifferentFromClientCache(HttpServletRequest req, FileAsset asset) {
        return asset.getMd5().equals(req.getHeader(HttpHeaders.IF_NONE_MATCH)) ||
                (msToSec(req.getDateHeader(HttpHeaders.IF_MODIFIED_SINCE)) >= msToSec(asset.getLastModified()));
    }
}


package io.robe.mail;

import io.dropwizard.Configuration;
import io.dropwizard.ConfiguredBundle;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import org.slf4j.Logger;

/**
 * Bundle class for mail implementation.
 */
public class MailBundle<T extends Configuration & HasMailConfiguration> implements ConfiguredBundle<T> {
    private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(MailBundle.class);

    /**
     * Initializes the environment.
     *
     * @param configuration the configuration object
     * @param environment   the io.robe.admin's {@link io.dropwizard.setup.Environment}
     * @throws Exception if something goes wrong
     */
    @Override
    public void run(T configuration, Environment environment) throws Exception {
        if (configuration.getMail() != null && configuration instanceof HasMailConfiguration && configuration instanceof Configuration) {
	        MailManager.setSender(new MailSender(configuration.getMail()));
        } else {
            LOGGER.warn("Bundle included but no configuration (mail) found at yml.");
        }
    }

    /**
     * Initializes the io.robe.admin bootstrap.
     *
     * @param bootstrap the io.robe.admin bootstrap
     */
    @Override
    public void initialize(Bootstrap<?> bootstrap) {
    }

}


package io.robe.admin.resources;

import io.dropwizard.hibernate.UnitOfWork;
import io.robe.admin.dto.TriggerInfoDTO;
import io.robe.admin.hibernate.dao.JobDao;
import io.robe.admin.hibernate.dao.TriggerDao;
import io.robe.admin.hibernate.entity.HJobInfo;
import io.robe.admin.hibernate.entity.HTriggerInfo;
import io.robe.admin.quartz.HibernateJobInfoProvider;
import io.robe.auth.Credentials;
import io.robe.auth.RobeAuth;
import io.robe.common.service.RobeService;
import io.robe.quartz.JobManager;
import io.robe.quartz.info.JobInfo;
import io.robe.quartz.info.TriggerInfo;
import org.hibernate.FlushMode;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerKey;

import javax.inject.Inject;
import javax.validation.Valid;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import static org.hibernate.CacheMode.GET;

@Path("triggers")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class TriggerResource {

    @Inject
    private JobDao jobDao;
    @Inject
    private TriggerDao triggerDao;

    /**
     * Create a {@link HTriggerInfo} resource.
     *
     * @param credentials auto fill by @{@link RobeAuth} annotation for authentication.
     * @param model       This is the one model of {@link HTriggerInfo}
     * @return create a {@link HTriggerInfo} resource.
     */
    @RobeService(group = "QuartzJob", description = "Create a HTriggerInfo resource.")
    @POST
    @UnitOfWork
    public HTriggerInfo create(@RobeAuth Credentials credentials, @Valid HTriggerInfo model) {
        //Save to the DB
        HJobInfo job = jobDao.findById(model.getJobOid());
        if (job == null) {
            throw new WebApplicationException("Job not found", Response.Status.NOT_FOUND);
        }
        if (!job.getProvider().equals(HibernateJobInfoProvider.class)) {
            throw new WebApplicationException("Trigger is not provided by an editable source.", Response.Status.PRECONDITION_FAILED);
        }
        HTriggerInfo record = triggerDao.create(model);
        return new TriggerInfoDTO(record);
    }

    /**
     * Update a HTriggerInfo resource  with the matches given id.
     *

     * Status Code:
     * Not Found  404
     * Not Matches 412
     *
     * @param credentials auto fill by @{@link RobeAuth} annotation for authentication.
     * @param id          This is  the oid of {@link HTriggerInfo}
     * @param model       This is the one model of {@link HTriggerInfo}
     * @return Update a  {@link HTriggerInfo} resource with the matches given id.
     */
    @RobeService(group = "QuartzJob", description = "Update a HTriggerInfo resource with the matches given id.")
    @PUT
    @UnitOfWork
    @Path("{id}")
    public HTriggerInfo update(@RobeAuth Credentials credentials, @PathParam("id") String id, @Valid HTriggerInfo model) {
        HJobInfo job = jobDao.findById(model.getJobOid());
        if (job == null) {
            throw new WebApplicationException("Job not found", Response.Status.NOT_FOUND);
        }
        if (!job.getProvider().equals(HibernateJobInfoProvider.class)) {
            throw new WebApplicationException("Trigger is not provided by an editable source.", Response.Status.PRECONDITION_FAILED);
        }
        if (!id.equals(model.getOid())) {
            throw new WebApplicationException("URL trigger id is not same with the payload id", Response.Status.FORBIDDEN);
        }
        HTriggerInfo entity = triggerDao.findById(id);
        if (entity == null) {
            throw new WebApplicationException("Trigger not found", Response.Status.NOT_FOUND);
        }
        triggerDao.detach(entity);
        model =  triggerDao.update(model);
        return new TriggerInfoDTO(model);
    }

    /**
     * Delete a HTriggerInfo resource  with the matches given id.
     *

     * Status Code:
     * Not Found  404
     * Not Matches 412
     *
     * @param credentials auto fill by @{@link RobeAuth} annotation for authentication.
     * @param id          This is  the oid of {@link HTriggerInfo}
     * @param model       This is the one model of {@link HTriggerInfo}
     * @return Delete a  {@link HTriggerInfo} resource  with the matches given id.
     */
    @RobeService(group = "QuartzJob", description = "Delete a HTriggerInfo resource with the matches given id.")
    @DELETE
    @UnitOfWork
    @Path("{id}")
    public HTriggerInfo delete(@RobeAuth Credentials credentials, @PathParam("id") String id, @Valid HTriggerInfo model) {
        if (!id.equals(model.getOid())) {
            throw new WebApplicationException(Response.status(412).build());
        }
        HTriggerInfo entity = triggerDao.findById(id);
        if (entity == null) {
            throw new WebApplicationException(Response.status(404).build());
        }
        return triggerDao.delete(entity);
    }

    @RobeService(group = "HJobInfo", description = "Returns all HTriggerInfo as a collection with the matches given job id.")
    @PUT
    @Path("{id}/schedule")
    @UnitOfWork(readOnly = true, cacheMode = GET, flushMode = FlushMode.MANUAL)
    public boolean schedule(@RobeAuth Credentials credentials, @PathParam("id") String id) {
        HTriggerInfo info = triggerDao.findById(id);
        HJobInfo jobEntity = jobDao.findById(info.getJobOid());
        if (info == null || jobEntity == null) {
            throw new WebApplicationException(Response.status(404).build());
        }
        JobInfo job = new HibernateJobInfoProvider().getJob(jobEntity.getJobClass());

        try {
            if (info.getType().equals(TriggerInfo.Type.CRON) ||
                    info.getType().equals(TriggerInfo.Type.SIMPLE)) {
                Trigger trigger = new HibernateJobInfoProvider().convert2Trigger(info, job);
                JobManager.getInstance().scheduleTrigger(trigger);
                return true;
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Returns all HTriggerInfo as a collection with the matches given job id.
     *
     * @param credentials auto fill by {@link RobeAuth} annotation for authentication.
     * @return all {@link HTriggerInfo} as a collection
     */
    @RobeService(group = "HJobInfo", description = "Returns all HTriggerInfo as a collection with the matches given job id.")
    @PUT
    @Path("{id}/unschedule")
    @UnitOfWork(readOnly = true, cacheMode = GET, flushMode = FlushMode.MANUAL)
    public boolean unschedule(@RobeAuth Credentials credentials, @PathParam("id") String id) {
        HTriggerInfo info = triggerDao.findById(id);
        HJobInfo jobEntity = jobDao.findById(info.getJobOid());

        if (info == null || jobEntity == null) {
            throw new WebApplicationException(Response.status(404).build());
        }
        JobInfo job = new HibernateJobInfoProvider().getJob(jobEntity.getJobClass());

        if (info == null) {
            throw new WebApplicationException(Response.status(404).build());
        }
        try {
            if (info.getType().equals(TriggerInfo.Type.CRON) ||
                    info.getType().equals(TriggerInfo.Type.SIMPLE)) {
                Trigger trigger = new HibernateJobInfoProvider().convert2Trigger(info, job);
                JobManager.getInstance().unScheduleTrigger(trigger);
                return true;
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Returns all HTriggerInfo as a collection with the matches given job id.
     *
     * @param credentials auto fill by {@link RobeAuth} annotation for authentication.
     * @return all {@link HTriggerInfo} as a collection
     */
    @RobeService(group = "HJobInfo", description = "Returns all HTriggerInfo as a collection with the matches given job id.")
    @PUT
    @Path("{id}/pause")
    @UnitOfWork(readOnly = true, cacheMode = GET, flushMode = FlushMode.MANUAL)
    public boolean pause(@RobeAuth Credentials credentials, @PathParam("id") String id) {
        HTriggerInfo info = triggerDao.findById(id);
        if (info == null) {
            throw new WebApplicationException(Response.status(404).build());
        }
        try {
            JobManager.getInstance().pauseTrigger(TriggerKey.triggerKey(info.getName(), info.getGroup()));
        } catch (SchedulerException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * Returns all HTriggerInfo as a collection with the matches given job id.
     *
     * @param credentials auto fill by {@link RobeAuth} annotation for authentication.
     * @return all {@link HTriggerInfo} as a collection
     */
    @RobeService(group = "HJobInfo", description = "Returns all HTriggerInfo as a collection with the matches given job id.")
    @PUT
    @Path("{id}/resume")
    @UnitOfWork
    public boolean resume(@RobeAuth Credentials credentials, @PathParam("id") String id) {
        HTriggerInfo info = triggerDao.findById(id);
        if (info == null) {
            throw new WebApplicationException(Response.status(404).build());
        }
        try {
            JobManager.getInstance().resumeTrigger(TriggerKey.triggerKey(info.getName(), info.getGroup()));
        } catch (SchedulerException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

}


package io.robe.hibernate.criteria.hql;

import io.robe.common.dto.Increment;
import io.robe.common.utils.Validations;
import io.robe.hibernate.criteria.api.CriteriaJoin;
import io.robe.hibernate.criteria.api.CriteriaParent;
import io.robe.hibernate.criteria.api.JoinRelation;
import io.robe.hibernate.criteria.api.criterion.Restriction;
import io.robe.hibernate.criteria.api.criterion.RestrictionList;
import io.robe.hibernate.criteria.api.projection.*;

import java.util.*;

/**
 * Created by kamilbukum on 30/01/2017.
 */
public class HqlUtil {

    /**
     *
     * @param criteria
     * @param projection
     * @param alias
     * @param elements
     * @param groupJoiner
     * @return
     */
    public static String selectForListByProjection(CriteriaParent criteria, Projection projection, String alias, TransformerUtil.Elements elements, StringJoiner groupJoiner){
        String result;
        if(projection instanceof IdentifierProjection) {
            result = criteria.getAlias() + "." + criteria.getMeta().getIdentityName() + getAsKey(criteria, criteria.getMeta().getIdentityName(), alias);
        }  else if(projection instanceof ProjectionElements) {
            ProjectionElements p = (ProjectionElements)projection;
            String elementAlias = alias != null ? alias: p.getProperty();
            if(elements.elementsMap == null) {
                elements.elementsMap = new LinkedHashMap<>();
            }
            elements.elementsMap.put(p.getProperty(), elementAlias);
            return null;
        } else if(projection instanceof PropertyProjection) {
            PropertyProjection p = (PropertyProjection)projection;
            result = criteria.getAlias() + "." + p.getProperty() + getAsKey(criteria, p.getProperty(), alias);
            if(p.isGrouped()) {
                groupJoiner.add( criteria.getAlias() + "." + p.getProperty());
            }
        } else if(projection instanceof FunctionProjection) {
            FunctionProjection pp = (FunctionProjection)projection;
            if(FunctionProjection.Type.COUNT == pp.getFnType() && Validations.isEmptyOrNull(pp.getProperty())) {
                return pp.getFnType().name() + "(1)" + getAsKey(criteria, "fn_" + pp.getFnType().name().toLowerCase(), alias);
            } else {
                return pp.getFnType().name() + "(" + criteria.getAlias() + "." + pp.getProperty() + ")" + getAsKey(criteria, "fn_" + pp.getProperty() + "_" + pp.getFnType().name().toLowerCase() , alias);
            }
        } else if(projection instanceof EnhancedProjection) {
            EnhancedProjection p = (EnhancedProjection)projection;
            result = selectForListByProjection(criteria, p.getProjection(), p.getAlias(),elements, groupJoiner);
        } else if(projection instanceof ProjectionList){
            ProjectionList p = (ProjectionList)projection;
            StringJoiner joiner = new StringJoiner(", ");
            for(int i = 0 ; i < p.getLength(); i++) {
                Projection childProjection = p.getProjection(i);
                String projectionString = selectForListByProjection(criteria, childProjection, null,elements, groupJoiner);
                if(!Validations.isEmptyOrNull(projectionString)) {
                    joiner.add(projectionString);
                }
            }
            result = joiner.toString();
        } else {
            throw new RuntimeException("Unknown Projection !"+ projection);
        }
        return result;
    }

    /**
     *
     * @param criteria
     * @param selectAlias
     * @param asAlias
     * @return
     */
    private static String getAsKey(CriteriaParent criteria, String selectAlias, String asAlias){
        String alias;
        if(asAlias != null) {
            alias = asAlias.replaceAll("\\.", "_0_");
        } else if(criteria.isRoot()) {
            alias = selectAlias;
        } else {
            alias =  criteria.getAlias() + "_0_" + selectAlias;
        }
        return  " AS "  + alias;
    }

    /**
     *
     * @param criteria
     * @param restrictions
     * @param restrictionJoiner
     * @param qJoiner
     * @param parameterMap
     * @param restrictionOrder
     */
    public static void generateRestrictions(
            CriteriaParent criteria,
            List<Restriction> restrictions,
            StringJoiner restrictionJoiner,
            StringJoiner qJoiner,
            Map<String, Object> parameterMap,
            Increment restrictionOrder){
        for(Restriction restriction: restrictions) {
            String result = null;
            switch (restriction.getOperator()) {
                case EQUALS:
                    result = restrictionToString(criteria, restriction, restrictionOrder.increment(), restriction.getValue(), "=", parameterMap);
                    break;
                case IS_NULL:
                    result = criteria.getAlias() + "." + restriction.getName() + " IS NULL";
                    break;
                case NOT_EQUALS:
                    result = criteria.getAlias() + "." + restrictionToString(criteria, restriction, restrictionOrder.increment(), restriction.getValue(), "!=", parameterMap);
                    break;
                case IS_NOT_NULL:
                    result = restriction.getName() + " IS NOT NULL";
                    break;
                case LESS_THAN:
                    result = restrictionToString(criteria, restriction, restrictionOrder.increment(), restriction.getValue(), " < ", parameterMap);
                    break;
                case LESS_OR_EQUALS_THAN:
                    result = restrictionToString(criteria, restriction, restrictionOrder.increment(), restriction.getValue(), " <= ", parameterMap);
                    break;
                case GREATER_THAN:
                    result = restrictionToString(criteria, restriction, restrictionOrder.increment(), restriction.getValue(), " > ", parameterMap);
                    break;
                case GREATER_OR_EQUALS_THAN:
                    result = restrictionToString(criteria, restriction, restrictionOrder.increment(), restriction.getValue(), " >= ", parameterMap);
                    break;
                case Q:
                    result = null;
                    qJoiner.add(criteria.getAlias() + "." + restriction.getName() + " LIKE " + ":" + restriction.getValueAlias());
                    parameterMap.putIfAbsent(restriction.getValueAlias(), getPercentValue(restriction));
                    break;
                case CONTAINS:
                    Object containsValue = getPercentValue(restriction);
                    result = restrictionToString(criteria, restriction, restrictionOrder.increment(), containsValue, " LIKE ", parameterMap);
                    break;
                case IN:
                    result = restrictionToString(
                            criteria,
                            restriction,
                            restrictionOrder.increment(),
                            restriction.getValue(),
                            " IN ", parameterMap
                    );
                    break;
                case AND:
                    StringJoiner andJoiner =  new StringJoiner(" AND ");
                    generateRestrictions(criteria, ((RestrictionList)restriction).getRestrictions(), andJoiner, qJoiner, parameterMap, restrictionOrder);
                    if(!"".equals(andJoiner.toString())) {
                        result = "( " +  andJoiner.toString() + " )";
                    }break;
                case OR:
                    StringJoiner orJoiner = new StringJoiner(" OR ");
                    generateRestrictions(criteria, ((RestrictionList)restriction).getRestrictions(), orJoiner, qJoiner, parameterMap, restrictionOrder);
                    if(!"".equals(orJoiner.toString())) {
                        result = "( " +  orJoiner.toString() + " )";
                    }
            }
            if(result != null) {
                restrictionJoiner.add(result);
            }
        }
    }
    /**
     *
     * @param criteria
     * @param restriction
     * @param operator
     * @return
     */
    private static String restrictionToString(CriteriaParent criteria, Restriction restriction, Integer order, Object value, String operator, Map<String, Object> parameterMap){
        if(Validations.isEmptyOrNull(restriction.getValueAlias())) {
            restriction.setValueAlias(criteria.getAlias() + "_" + restriction.getName()+ "_" + order);
        }
        parameterMap.put(restriction.getValueAlias(), value);
        return criteria.getAlias() + "." + restriction.getName() + operator + (value instanceof Collection ? (  "(:" + restriction.getValueAlias() + ")"): ":" + restriction.getValueAlias());
    }

    private static Object getPercentValue(Restriction restriction) {
        if(restriction.getValue() != null) {
            return "%" + restriction.getValue() + "%";
        }
        return  "%%";
    }

    /**
     * Generates Join Query for the given JoinCriteria
     * @param criteriaJoin
     * @return
     */
    public static String joinToString(CriteriaJoin criteriaJoin) {
        StringBuilder builder = new StringBuilder("LEFT OUTER JOIN ")
                .append(criteriaJoin.getEntityClass().getName())
                .append(" ")
                .append(criteriaJoin.getAlias())
                .append(" ")
                .append(" ON ");

        if(criteriaJoin.getJoinRelations().size() == 0) {
            throw new RuntimeException("Not found any Join Relations in " + criteriaJoin.getAlias() + " Join Criteria ! ");
        }

        StringJoiner joiner = new StringJoiner(" AND ");
        List<JoinRelation> relationList = criteriaJoin.getJoinRelations();
        for(JoinRelation joinRelation: relationList) {
            StringBuilder relationBuilder = new StringBuilder("\n")
                    .append(joinRelation.getRelationCriteria().getAlias())
                    .append(".")
                    .append(joinRelation.getRelationField())
                    .append("=")
                    .append(joinRelation.getJoinedCriteria().getAlias())
                    .append(".")
                    .append(joinRelation.getJoinedField());
            joiner.add(relationBuilder.toString());
        }

        if(joiner.length() > 0) {
            builder.append(joiner.toString());
        }
        return builder.toString();
    }
}


package io.robe.auth.token.jersey;

import io.robe.auth.token.BasicToken;
import io.robe.auth.token.configuration.TokenBasedAuthConfiguration;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.Response;
import java.io.IOException;

/**
 * The response jersey for creating or refreshing AuthTokens. Refreshing controlled by created token.
 */
public class TokenBasedAuthResponseFilter implements ContainerResponseFilter {
    private static final Logger LOGGER = LoggerFactory.getLogger(TokenBasedAuthResponseFilter.class);
    private static String tokenKey;
    private static String cookieSentence = "";
    private static String logoutPath = "";

    /**
     * Creates a valid token cookie template with the given configuration.
     *
     * @param configuration
     */
    public TokenBasedAuthResponseFilter(TokenBasedAuthConfiguration configuration) {
        this.tokenKey = configuration.getTokenKey();
        String domain = configuration.getDomain();
        String path = configuration.getPath();
        if (configuration.getMaxage() > 0l)
            cookieSentence += "; Max-Age=" + configuration.getMaxage();//+ "; Expires={expireDate}";
        if (domain != null && !domain.equals(""))
            cookieSentence += "; Domain=" + domain + ";";
        if (path != null && !path.equals(""))
            cookieSentence += "; Path=" + path;
        if (configuration.isSecure()) {
            cookieSentence += "; Secure;";
        }
        cookieSentence += "; HttpOnly";

        logoutPath = configuration.getLogoutPath();

    }

    /**
     * Combines the token and cookie sentence
     *
     * @param token
     * @return
     */
    public static String getTokenSentence(BasicToken token) throws Exception {
        if (token == null)
            return tokenKey + "=" + cookieSentence;
        String sentence = tokenKey + "=" + token.getTokenString() + cookieSentence;
        //TODO: Learn how to calculate expire according to the browser time.
//        sentence = sentence.replace("{expireDate}", token.getExpirationDate().toGMTString());
        return sentence;
    }

    /**
     * Checks the expiration date of token.
     * Renews and puts at header of response.
     *
     * @param requestContext
     * @param responseContext
     * @return
     */
    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
        String authToken = extractAuthTokenFromCookieList(requestContext.getHeaders().getFirst("Cookie"));
        if (authToken != null && authToken.length() != 0) {
            try {
                BasicToken token = new BasicToken(authToken);
                if (token.isExpired()) {
                    LOGGER.debug("ExpireDate : " + token.getExpirationDate().toString());
                    LOGGER.debug("Now: " + DateTime.now().toDate().toString());
                    responseContext.getHeaders().putSingle("Set-Cookie", getTokenSentence(null));
                    responseContext.setStatusInfo(Response.Status.UNAUTHORIZED);
                    responseContext.setEntity("Token expired. Please login again.");
                    LOGGER.info("Token expired. Please login again.");
                } else {
                    token.setExpiration(token.getMaxAge());
                    if (!logoutPath.equals(requestContext.getUriInfo().getPath())) {
                        String cookie = getTokenSentence(token);
                        responseContext.getHeaders().putSingle("Set-Cookie", cookie);
                    }
                }

            } catch (Exception e) {
                LOGGER.error("Token re-creation failed", e.getMessage());
                responseContext.setStatusInfo(Response.Status.UNAUTHORIZED);

            }
        }
    }

    /**
     * Extracts the accesstoken from cookies
     *
     * @param cookieList
     * @return
     */
    private String extractAuthTokenFromCookieList(String cookieList) {
        if (cookieList == null || cookieList.length() == 0) {
            return null;
        }
        String[] cookies = cookieList.split(";");
        for (String cookie : cookies) {
            if (cookie.trim().startsWith(tokenKey)) {
                return cookie.trim().substring(tokenKey.length() + 1);
            }
        }
        return null;
    }

}


package io.robe.guice;

import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.servlet.GuiceFilter;
import io.dropwizard.jersey.setup.JerseyEnvironment;
import io.dropwizard.setup.Environment;
import org.glassfish.jersey.server.model.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.Path;
import java.lang.reflect.Type;

//Copied from https://github.com/HubSpot/dropwizard-guice/blob/master/src/main/java/com/hubspot/dropwizard/guice/JerseyUtil.java;

/**
 * Functionality used to help link Guice with Jersey
 */
public class JerseyUtil {

    private static final Logger logger = LoggerFactory.getLogger(JerseyUtil.class);

    /**
     * Registers any Guice-bound providers or root resources.
     */
    public static void registerGuiceBound(Injector injector, final JerseyEnvironment environment) {
        while (injector != null) {
            for (Key<?> key : injector.getBindings().keySet()) {
                Type type = key.getTypeLiteral().getType();
                if (type instanceof Class) {
                    Class<?> c = (Class) type;
                    if (isProviderClass(c)) {
                        logger.info("Registering {} as a provider class", c.getName());
                        environment.register(c);
                    } else if (isRootResourceClass(c)) {
                        // Jersey rejects resources that it doesn't think are acceptable
                        // Including abstract classes and interfaces, even if there is a valid Guice binding.
                        if (Resource.isAcceptable(c)) {
                            logger.info("Registering {} as a root resource class", c.getName());
                            environment.register(c);
                        } else {
                            logger.warn("Class {} was not registered as a resource. Bind a concrete implementation instead.", c.getName());
                        }
                    }

                }
            }
            injector = injector.getParent();
        }
    }

    private static boolean isProviderClass(Class<?> c) {
        return c != null && c.isAnnotationPresent(javax.ws.rs.ext.Provider.class);
    }

    private static boolean isRootResourceClass(Class<?> c) {
        if (c == null) {
            return false;
        }

        if (c.isAnnotationPresent(Path.class)) {
            return true;
        }

        for (Class i : c.getInterfaces()) {
            if (i.isAnnotationPresent(Path.class)) {
                return true;
            }
        }

        return false;
    }

    public static void registerGuiceFilter(Environment environment) {
        environment.servlets().addFilter("Guice Filter", GuiceFilter.class)
                .addMappingForUrlPatterns(null, false, environment.getApplicationContext().getContextPath() + "*");
    }
}