/**
   * Makes the Mandelbrot image.
   *
   * @param width the width
   * @parah height the height
   * @return the image
   */
  public BufferedImage makeMandelbrot(int width, int height) {
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    WritableRaster raster = image.getRaster();
    ColorModel model = image.getColorModel();

    Color fractalColor = Color.red;
    int argb = fractalColor.getRGB();
    Object colorData = model.getDataElements(argb, null);

    for (int i = 0; i < width; i++)
      for (int j = 0; j < height; j++) {
        double a = XMIN + i * (XMAX - XMIN) / width;
        double b = YMIN + j * (YMAX - YMIN) / height;
        if (!escapesToInfinity(a, b)) raster.setDataElements(i, j, colorData);
      }
    return image;
  }
  public void setPixels(
      int x, int y, int w, int h, ColorModel model, int pix[], int off, int scansize) {
    int lineOff = off;
    int poff;

    if (src != null) {
      src.checkSecurity(null, false);
    }

    // REMIND: What if the model doesn't fit in default color model?
    synchronized (this) {
      if (bimage == null) {
        if (cmodel == null) {
          cmodel = model;
        }
        createBufferedImage();
      }

      int[] storage = new int[w];
      int yoff;
      int pixel;

      if (cmodel instanceof IndexColorModel) {
        // REMIND: Right now we don't support writing back into ICM
        // images.
        convertToRGB();
      }

      if ((model == cmodel) && (biRaster instanceof IntegerComponentRaster)) {
        IntegerComponentRaster iraster = (IntegerComponentRaster) biRaster;

        if (off == 0 && scansize == w) {
          iraster.setDataElements(x, y, w, h, pix);
        } else {
          // Need to pack the data
          for (yoff = y; yoff < y + h; yoff++, lineOff += scansize) {
            System.arraycopy(pix, lineOff, storage, 0, w);
            iraster.setDataElements(x, yoff, w, 1, storage);
          }
        }
      } else {
        if (model.getTransparency() != model.OPAQUE && cmodel.getTransparency() == cmodel.OPAQUE) {
          convertToRGB();
        }

        if (isDefaultBI) {
          IntegerComponentRaster iraster = (IntegerComponentRaster) biRaster;
          int[] data = iraster.getDataStorage();
          if (cmodel.equals(model)) {
            int sstride = iraster.getScanlineStride();
            int doff = y * sstride + x;
            for (yoff = 0; yoff < h; yoff++, lineOff += scansize) {
              System.arraycopy(pix, lineOff, data, doff, w);
              doff += sstride;
            }
            // Note: manual modification of pixels, mark the
            // raster as changed
            iraster.markDirty();
          } else {
            for (yoff = y; yoff < y + h; yoff++, lineOff += scansize) {
              poff = lineOff;
              for (int i = 0; i < w; i++) {
                storage[i] = model.getRGB(pix[poff++]);
              }
              iraster.setDataElements(x, yoff, w, 1, storage);
            }
          }

          availinfo |= ImageObserver.SOMEBITS;
        } else {
          Object tmp = null;

          for (yoff = y; yoff < y + h; yoff++, lineOff += scansize) {
            poff = lineOff;
            for (int xoff = x; xoff < x + w; xoff++) {
              pixel = model.getRGB(pix[poff++]);
              tmp = cmodel.getDataElements(pixel, tmp);
              biRaster.setDataElements(xoff, yoff, tmp);
            }
          }
          availinfo |= ImageObserver.SOMEBITS;
        }
      }
    }

    // Can't do this here since we might need to transform/clip
    // the region
    if (((availinfo & ImageObserver.FRAMEBITS) == 0)) {
      newInfo(image, ImageObserver.SOMEBITS, x, y, w, h);
    }
  }
  /**
   * Creates the image Modus 0 for creating the image with the color given from the material Modus 1
   * for creating the image with one color for every normal of every geometry in the scene Modus 2
   * for creating the image in Cel Shading
   *
   * @param camera the camera
   * @param modus the modus
   * @return the buffered image
   * @throws will be thrown if the given argument was null
   */
  public BufferedImage createImage(final Camera camera, final int modus) {
    if (camera == null) {
      throw new IllegalArgumentException("The camera cannot be null!");
    }
    if (modus < 0 || modus > 3) {
      throw new IllegalArgumentException(
          "Only 0 for normal Raytracing or 1 for displaying the normals of the image");
    }
    long zstVorher;
    long zstNachher;
    zstVorher = System.currentTimeMillis();

    Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    final WritableRaster raster = image.getRaster();
    // get the color model from the created image
    final ColorModel model = image.getColorModel();
    Ray ray;

    /*

    for (int i = 0; i < image.getWidth(); i++) {
           final int ii =i;
           executor.execute(new Runnable() {
               public void run() {
                   for (int j = 0; j < image.getHeight(); j++) {
                       raster.setDataElements(ii, image.getHeight()-j-1, model.getDataElements(
                               getPixelColor(width,height,ii,j,world,camera),0, null));
                   }
               }
           });
       }

    */
    for (int i = 0; i < width; i++) {
      for (int j = 0; j < height; j++) {

        ray = camera.rayFor(width, height, i, j);
        // created the image with the colors given from the materials
        if (modus == 0) {
          raster.setDataElements(
              i, height - j - 1, model.getDataElements(getColor(ray).getIntFromColor(), null));
        }
        // created the image with colors for each normal from every object
        if (modus == 1) {
          raster.setDataElements(
              i,
              height - j - 1,
              model.getDataElements(getColorNormal(ray).getIntFromColor(), null));
        }
        if (modus == 3) {
          raster.setDataElements(
              i,
              height - j - 1,
              model.getDataElements(getColorCelShading(ray).getIntFromColor(), null));
        }
      }
    }

    if (modus == 2) {
      image = createCelshading();
    }
    zstNachher = System.currentTimeMillis();
    System.out.println("Zeit benötigt: " + ((zstNachher - zstVorher)) + " sec");
    return image;
    /*

    executor.shutdown();
    try {
        executor.awaitTermination(100, TimeUnit.SECONDS);
    }
    catch (InterruptedException e) {
        // what should happen if timeout was hit
    }

    zstNachher = System.currentTimeMillis();
    System.out.println("Zeit benötigt: " + ((zstNachher - zstVorher)) + " sec");
    return image;
    */

  }