/*
 * Copyright 2007 nori090
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.coderepos.nori090.peercast.proxy;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author nori090
 * @version $Rev: 147 $ $Date: 2008-08-15 00:51:07 +0900 (Fri, 15 Aug 2008) $
 */
public class YpHttpProxy {
    static final String HTTP_ELEMENT_CHARSET = "US-ASCII";

    ConcurrentHashMap<String, Content> cache = new ConcurrentHashMap<String, Content>();

    public YpHttpProxy() {
        super();
        Thread t = new Thread( this.new HttpProxy(), "PCRawProxy_HttpProxy" );
        t.start();
    }

    private class HttpProxy
        implements Runnable {

        @Override
        public void run() {
            try {
                ServerSocket serverSocket = new ServerSocket( 8080 );
                while ( true ) {
                    Socket sock = serverSocket.accept();
                    Thread t = new Thread( new ProcessRequest( sock ), "PCRawProxy_ProcessRequest" );
                    t.start();
                }
            }
            catch ( IOException e ) {
                e.printStackTrace();
            }
        }
    }

    private class ProcessRequest
        implements Runnable {
        private Socket socket;

        public ProcessRequest( Socket sock ) {
            super();
            this.socket = sock;
        }

        @Override
        public void run() {
            try {
                BufferedInputStream clientIn = new BufferedInputStream( socket.getInputStream() );
                BufferedOutputStream clientOut = new BufferedOutputStream( socket.getOutputStream() );
                YpRequest yprequest = new YpRequest( clientIn );
                byte[] request = yprequest.request;
                Content c = cache.get( yprequest.url );
                if ( c == null || ( System.currentTimeMillis() - c.lastupdate ) > ( 60 * 15 * 1000 ) ) {
                    if ( c == null ) {
                        c = new Content();
                        cache.put( yprequest.url, c );
                    }
                    String hostname = yprequest.host;
                    int port = 80;
                    int pos = hostname.indexOf( ":" );
                    if ( pos > 0 ) {
                        port = Integer.parseInt( hostname.substring( pos + 1 ) );
                        hostname = hostname.substring( 0, pos );
                    }
                    Socket serv = new Socket( hostname, port );
                    if ( serv != null ) {
                        serv.setSoTimeout( 3000 );
                        BufferedInputStream serverIn = new BufferedInputStream( serv.getInputStream() );
                        BufferedOutputStream serverOut = new BufferedOutputStream( serv.getOutputStream() );
                        serverOut.write( request, 0, request.length );
                        serverOut.flush();
                        YpResponse.getResponse( serverIn, c );
                        serverOut.close();
                        serverIn.close();
                    }
                    serv.close();
                }
                if ( c.raw ) {
                    c.cache = c.pcRaw.getData();
                    c.lastupdate = System.currentTimeMillis();
                }
                clientOut.write( c.cache, 0, c.cache.length );
                clientOut.flush();
                clientIn.close();
                clientOut.close();
                socket.close();
            }
            catch ( IOException e ) {
                e.printStackTrace();
            }
            finally {
                close( socket );
            }
        }

        void close( Socket s ) {
            try {
                s.shutdownOutput();
            }
            catch ( Exception e ) {
                // ignore
            }
            try {
                s.close();
            }
            catch ( Exception e ) {
                // ignore
            }
        }
    }

    public static void main( String[] args ) {
        new YpHttpProxy();
    }
}
