
package ru.sakva.bsh;

 import java.applet.*;
 import java.awt.*;
 import java.awt.event.*;
 import java.awt.image.*;
 import java.net.*;
 import java.io.*;
 import java.util.*;

/**
 Shelf is Java applet for presentation of different data
 (file, weblinks, etc.) as books on bookshelves.
*/

 public class Shelf extends Applet
   implements MouseListener,MouseMotionListener,ComponentListener
/* * */ { /* * */
 static protected final int shelfH=6;
 static protected Hashtable icons = new Hashtable();


/**  Color of walls */
 public Color shelfColor = SystemColor.window;

/**  Color of shelves */
 public Color plainColor = SystemColor.control;

 protected Book taken;
 protected int takenNum;
 int border=0;

 protected Book[] books;
 boolean vertical=false;
 Image im=null;
 int imU,imV,imW,imH;
 int msU,msV;
 int waitTime=1000;

 boolean upward=true;
 boolean column=true;
 boolean turned=false;
 boolean boxes=false;

 int[] p = new int[7];
 int[] q = new int[7];

 Properties props;
 String encoding; //="Cp1251";

/** Applet init */
 public void init()
{
 try { encoding=System.getProperty("file.encoding"); }
 catch(Exception ex){ }
 addComponentListener(this);
 }

 String getProp(String pname)
{
 String str=getParameter(pname);
 if(str == null && props != null)str=props.getProperty(pname);
 return str;
 }

/**  Allocate array for books */
 public void reserve(int n)
{
 books = new Book[n]; int i=0; while(i < n)books[i++]=new Book();
 }

 void loadProps(String arg)
{
 props = new Properties();
 try
   {
    InputStream pin= // (new URL(getCodeBase(),arg)).openStream();
      Shelf.class.getResourceAsStream("/"+arg);
    InputStreamReader isr = null;
    try { isr =  new InputStreamReader(pin,encoding);}
    catch(Exception ex){ isr =  new InputStreamReader(pin); }
    BufferedReader br = new BufferedReader(isr);
    String str; int ind;
    while((str = br.readLine()) != null)
      {
       if((ind = str.indexOf( '=' )) == -1)
         props.put( str.toLowerCase(), "" );
       else props.put
         (str.substring(0,ind).toLowerCase(),str.substring(ind+1).trim());
       }
    pin.close();
    }
 catch(Exception ex){ System.out.println(ex); }
 }

 private Image rotImg(int imga,int imgb,int w,Book book,int ang)
{
 Image image = createImage(imga,imgb);
 Graphics gr = image.getGraphics();

 if(ang == 0)
   {
    gr.setColor(book.coverColor);
    gr.fillRect(0,0,imga,imgb);
    gr.setColor(book.titleColor);
    book.drawTitle(gr,0,0,w);
    }
 else
   {
    gr.setColor(Color.black);
    gr.fillRect(0,0,imga,imgb);
    gr.setColor(Color.white);
    book.drawTitle(gr,0,0,w);
    Rot90 imf = new Rot90();
    imf.angle=(book.turned())?-ang:ang;
    if(book.upward())imf.angle=-imf.angle;
    imf.asIs=false;
    imf.front=book.titleColor.getRGB();
    imf.back=0x00000000;
    image = createImage(new FilteredImageSource(image.getSource(),imf));
    }
 return image;
 }

/**  Get params from input or HTML */
 public void getParams()
{
 int i,k;
 int n=0;
 String par,s;
 MediaTracker mtr = new MediaTracker(this);
 Book book;

// Get common and default parameters if available
 if((par=getProp("encoding"))!=null)encoding=new String(par);
 if((par=getParameter("input"))!=null)loadProps(par);
 if((par=getProp("wait"))!=null)waitTime=Integer.parseInt(par);
 if((par=getProp("border"))!=null)border=Integer.parseInt(par);
 if((par=getProp("putbooks"))!=null)
   { if(par.startsWith("vert"))vertical=true; }
 if((par=getProp("title.direction"))!=null)
   {
    upward = par.equalsIgnoreCase("upward");
    column = par.equalsIgnoreCase("column");
    }
 if((par=getProp("book.turned"))!=null)turned = par.equalsIgnoreCase("yes");
 if((par=getProp("wall.color"))!=null)
   shelfColor=new Color(Integer.parseInt(par,16));
 if((par=getProp("shelf.color"))!=null)
   plainColor=new Color(Integer.parseInt(par,16));
 if((par=getProp("cover.color"))!=null)
   Book.defaultCoverColor=new Color(Integer.parseInt(par,16));
 if((par=getProp("title.color"))!=null)
   Book.defaultTitleColor=new Color(Integer.parseInt(par,16));
 if((par=getProp("book.min"))!=null) Book.hmin=Integer.parseInt(par);
 if((par=getProp("book.max"))!=null) Book.hmax=Integer.parseInt(par);
 if((par=getProp("book.volume"))!=null)Book.volume=Integer.parseInt(par);
 if((par=getProp("book.box"))!=null)boxes = par.equalsIgnoreCase("yes");
 if((par=getProp("font.size"))!=null)Book.initFonts(Integer.parseInt(par));
 if((par=getProp("book.size"))!=null)
   {
    Book.height=(Integer.parseInt(par));
    Book.width=Book.height/4;
    Book.thickness=Book.height/8;
    }
 if((par=getProp("book.thickness"))!=null)
   { Book.thickness=(Integer.parseInt(par)); }

// Get parameters for each book
 if((par=getProp("books.number"))!=null)
   {
    n=(Integer.parseInt(par)); reserve(n);
    i=0; while(i < n)
      {
       book=books[i];
       book.upward(upward);
       book.chinese(column);
       book.turn(turned);
       book.box(boxes);
       s="$"+String.valueOf(i+1);
       if((par=getProp(s+".title"))!=null)book.setTitle(par);
       if((par=getProp(s+".ref"))!=null)book.setReference(par);
       if((par=getProp(s+".title.direction"))!=null)
         {
          book.upward(par.equalsIgnoreCase("upward"));
          book.chinese(par.equalsIgnoreCase("column"));
          }
       if((par=getProp(s+".volume"))!=null)
         book.setVolume(Integer.parseInt(par,16));
       if((par=getProp(s+".turned"))!=null)book.turn(par.equalsIgnoreCase("yes"));
       if((par=getProp(s+".box"))!=null)book.box(par.equalsIgnoreCase("yes"));
       if((par=getProp(s+".icon"))!=null)
         {
          try  // if book has picture try to get it
            {  // is picture in hashtable also?
             Image img1 = (Image)icons.get(par);
             if(img1 == null)  // if picture is not in hastable yet
               {
                InputStream ins = Shelf.class.getResourceAsStream("/"+par);
                Image src=null;
                if(ins != null)
                  {
                   int l = ins.available();
                   byte[] b = new byte[l];
                   k=0; while(k < l)b[k++]=(byte)ins.read(); ins.close();
                   src = getToolkit().createImage(b,0,l);
                   }
                else src = getImage(new URL(getDocumentBase(),par));
                if(src != null)
                  {
                   if(vertical == false || book.turned())
                     { //  if books are horisontal or turned rotate picture
                      Rot90 imf = new Rot90();
                      if(vertical)imf.angle=180;
                      else imf.angle = book.upward()?90:-90;
                      ImageProducer imp =
                        new FilteredImageSource(src.getSource(),imf);
                      img1 = createImage(imp);
                      }
                   else img1=src;
                   mtr.addImage(img1,i); //,-1,book.c);
                   icons.put(par,img1);  // put picture in hashtable
                   }
                }
             book.setIcon(img1);
             }
          catch(Exception e){ /*System.out.println(e);*/ }
          }
       if((par=getProp(s+".title.color"))!=null)
          book.titleColor=new Color(Integer.parseInt(par,16));
       if((par=getProp(s+".cover.color"))!=null)
          book.coverColor=new Color(Integer.parseInt(par,16));
       i++;
       }
    }
//  Wait for all pictures
 try { mtr.waitForAll(waitTime); }catch(Exception ex){ }

 if(books != null)
   {  // some tricks to make vertical text
    Image ic,img2;
    Graphics g;
    int w,bookW,bookH,book0;
    boolean bookTurned,chinese;
    i=0; while(i < books.length)
      {
       if((book = books[i])!=null)
         {
          chinese = book.chinese();
          if(vertical || chinese)
            {
             bookW=book.c; bookH=book.b;
             bookTurned=book.turned();
             int im2w=bookW; int im2h=bookH;
             if(!vertical) { im2w=bookH; im2h=bookW; }
             img2 = createImage(im2w,im2h);
             g = img2.getGraphics();
             g.setColor(book.coverColor);
             g.fillRect(book.u,book.v,im2w,im2h);
             ic = book.icon; w=0;
             if(ic != null)
               {
                w = (int)((float)ic.getHeight(this)/ic.getWidth(this)*bookW);
                if(vertical)g.drawImage(ic,0,bookTurned?bookH-w:0,bookW,w,this);
                else        g.drawImage(ic,bookTurned?bookH-w:0,0,bookW,w,this);
                }
             book0=bookH-w;

             if(vertical)
               {
                if(chinese)g.drawImage(rotImg(bookW,book0,w,book,0),
                     0,bookTurned?0:w,bookW,book0,this);
                else g.drawImage(rotImg(book0,bookW,w,book,90),
                     0,bookTurned?0:w,bookW,book0,this);
                }
             else g.drawImage(rotImg(bookW,bookH,w,book,-90),
                  bookTurned?0:w,0,book0,bookW,this);
             book.icon = img2;
             }
          }
       i++;
       }
    }
 }

/** Creates offscreen image */
 public void createOffScreen()
{
 Dimension sz = getSize();
 imW=sz.width-2*border; imH=sz.height-2*border;
 imU=imV=0;
 im=createImage(imW,imH);
 }

/** Redraw books and shelves */
 public void refresh()
{
 if(im==null)createOffScreen();
 if(im != null)draw(im.getGraphics());
 repaint();
 }

/**
 Draw one shelf
 @param ig  -  Graphics to draw on
 @param v   -  thickness (height) odf shelf
*/
 public void drawShelf(Graphics ig,int v)
{
 int l = Book.width;
 p[0]=0; p[1]=imW-l-3; p[2]=p[3]=imW-1; p[4]=l+2; p[5]=0;
 q[0]=q[1]=v+shelfH; q[2]=q[1]-l-2; q[3]=q[2]-shelfH;
 q[4]=q[3]; q[5]=v;
 ig.setColor(plainColor); ig.fillPolygon(p,q,6);
 ig.setColor(Color.black);
 ig.drawPolygon(p,q,6);

 ig.drawLine(p[0],v,p[1],v);
 ig.drawLine(p[1],v,p[2],q[3]);
 ig.drawLine(p[1],q[1],p[1],v);
 ig.drawLine(p[4],q[4],p[0],v);
 }

/** Draw shelves and books */
 public void draw(Graphics ig)
{
 int u,v,i,j,k,d;
 Book book;
 int[] top = new int[32];  int nt=0;

 int l = Book.width;
 ig.setColor(shelfColor); ig.fillRect(0,0,imW,imH);
 ig.setColor(Color.black);
// ig.drawLine(l,0,l,imH);

 if(books != null)
   {
    if(vertical)
      {
       u=2; v=imH-Book.height-shelfH*2; d=shelfH+Book.height+6;
       top[nt++]=0;
       k=0; j=0; while(j < books.length)
         {
          if((book=books[j]) != null)
            {
             if(u+book.a+book.c+2 > imW)
               {
                top[nt++]=j;
                i=0; while(i < j){ if(books[i]!=null)books[i].v-=d; i++; }
                u=2;
                }
             book.u=u+2; book.v=v-2;
             u+=book.c+2;
             if(book.selected()){ book.u-=4; book.v+=4; }
             }
          j++;
          }

       v=imH-shelfH*2;
       k=books.length; j=nt; while(--j >= 0)
         {
          drawShelf(ig,v);
          i=top[j]; while(i < k)
            { if(books[i] != null)books[i].drawVertical(ig); i++; }
          k=top[j];
          v-=d;
          }
       }
    else
      {
       u=2; v=Book.width;
       k=0; j=0; while(j < books.length)
         {
          if((book=books[j]) != null)
            {
             v+=book.c+1;
             if(v > imH-2*shelfH)
               {
                top[nt++]=j;
                d=(imH-2*shelfH)-(v-book.c-1);
                i=k; while(i < j){ if(books[i] != null)books[i].v+=d; i++; }
                k=j; v=Book.width+book.c+1; u+=Book.height+6;
                }
             book.u=u+2; book.v=v-book.c-3;
             if(book.selected()){ book.u-=4; book.v+=4; }
             }
          j++;
          }
       top[nt++]=j;
       d=imH-2*shelfH-v;
       i=k; while(i < j){ if(books[i]!=null)books[i].v+=d; i++; }

       drawShelf(ig,imH-shelfH*2);
       k=0; j=0; while(j < nt)
         {
          i=top[j]; while(--i >= k)
            if(books[i] != null)books[i].drawHorisontal(ig);
          k=top[j++];
          }
       }
    }
 }

// Draw border around Applet
 void drawBorder(Graphics g)
{
 int w = imW+2*border; int h = imH+2*border;
 int h1=h-1; int h4=h-border; int w1=w-1; int w4=w-border;
 g.setColor(shelfColor);
 g.fill3DRect(0,0,w,border,true);
 g.fill3DRect(0,h4,w,border,true);
 g.fill3DRect(0,border,border,h4-border,true);
 g.fill3DRect(w4,border,border,h4-border,true);
 g.clipRect(border+1,border+1,w-2*border-1,h-2*border-1);
 }

// update (from Component)
 public void update(Graphics g)
{
 if(im != null)
   {
    Dimension sz = getSize();
    g.clearRect
      (imU+sz.width+border,border,sz.width-imU-2*border,sz.height-2*border);
    g.drawImage(im,imU+border,imV+border,this);
    if(taken != null)
      {
       if(vertical)taken.drawVertical(g);
       else        taken.drawHorisontal(g);
       }
    }
 if(border != 0)drawBorder(g);
 }

// paint (from Component)
 public void paint(Graphics g)
{
 update(g);
 }

/** Returns index of book with coordinatex (u,v) */
 public int getBookIndex(int u,int v)
{
 int i=-1;
 Book book;
 int u1,u2,v1,v2;

 if(books != null)
   {
    i=0; while(i < books.length)
      {
       if((book=books[i])!=null)
         {
          u1=book.u+border; v1=book.v+border;
          u2 = u1+(vertical?book.c:book.b);
          v2 = v1+(vertical?book.b:book.c);
          if(u1 < u && u < u2 && v1 < v && v < v2)break;
          }
       i++;
       }
    }
 return i;
 }

 static ColorModel dcm = new DirectColorModel(24,0xff0000,0xff00,0xff);

/************ ImageObserver implementation */

 public boolean imageUpdate(Image img,int s,int x,int y,int w,int h)
{ return ( (s & ALLBITS) != ALLBITS) && ( (s & (ABORT|ERROR))==0); }

/************ MouseListener implementation */

 public void mousePressed(MouseEvent me)
{ msU=me.getX(); msV=me.getY(); }

 public void mouseReleased(MouseEvent me){ }

 public void mouseEntered(MouseEvent me)
{ setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); }

 public void mouseExited(MouseEvent me)
{ setCursor(Cursor.getDefaultCursor()); }

 public void mouseClicked(MouseEvent me){ }

 public void mouseMoved(MouseEvent me){ }

 public void mouseDragged(MouseEvent me)
{
 int u = me.getX();
 int du = u-msU; msU=u;
 if(du != 0)
   {
    u=imU+du;
    if(16-getSize().width < u && u <= 0){ imU = u; repaint(); }
    }
 }

/************ ComponentListener implementation */

 public void componentHidden(ComponentEvent ce){  }
 public void componentMoved(ComponentEvent ce){  }
 public void componentResized(ComponentEvent ce){  }

 public void componentShown(ComponentEvent ce)
{
 if(im == null){ createOffScreen(); refresh(); }
 }

/* * */ } /* * */


