/*******************************************************************************
Jimm - Mobile Messaging - J2ME ICQ clone
Copyright (C) 2003-04  Jimm Project

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
********************************************************************************
File: src/jimm/comm/SearchAction.java
 Version: 0.5.1  Date: 2006/10/31
Author(s): Andreas Rossbacher
*******************************************************************************/

package jimm.comm;

import javax.microedition.lcdui.Alert;

import jimm.Jimm;
import jimm.JimmException;
import jimm.MainMenu;
import jimm.Options;
import jimm.Search;
import jimm.util.ResourceBundle;

import java.io.ByteArrayOutputStream;


public class SearchAction extends Action
{
    
    // States of search mission
    public static final int STATE_ERROR                  = -1;
    public static final int STATE_UIN_SEARCH_SENT        = 1;
    public static final int STATE_EMAIL_SEARCH_SENT      = 2;
    public static final int STATE_WHITEPAGES_SEARCH_SENT = 3;
    public static final int STATE_FIRSTRESULT_RECEIVED   = 4;
    public static final int STATE_LASTRESULT_RECEIVED    = 5;
    public static final int STATE_SEARCH_FINISHED        = 6;
    public static final int STATE_SEARCH_CANCELED        = 7;
    
    // TLVs used in LE format
    public static final int TLV_TYPE_UIN                 = 0x3601; // long (4 byte)
    public static final int TLV_TYPE_NICK                = 0x5401; // String (2 byte length + string)
    public static final int TLV_TYPE_FIRSTNAME           = 0x4001; // String (2 byte length + string)
    public static final int TLV_TYPE_LASTNAME            = 0x4A01; // String (2 byte length + string)
    public static final int TLV_TYPE_EMAIL               = 0x5E01; // String (2 byte length + string + 1 byte email code)
    public static final int TLV_TYPE_CITY                = 0x9001; // String (2 byte length + string)
    public static final int TLV_TYPE_KEYWORD             = 0x2602; // String (2 byte length + string)
    public static final int TLV_TYPE_GENDER              = 0x7C01; // UINT8 (1 byte: 1 - female, 2 - male)
    public static final int TLV_TYPE_ONLYONLINE          = 0x3002; // UINT8 (1 byte:  1 - search online, 0 - search all)
    public static final int TLV_TYPE_AGE                 = 0x6801; // 
    
    
    // Search action was called by
    public static final int CALLED_BY_SEARCHUSER         = 0;
    public static final int CALLED_BY_ADDUSER            = 1;
    
    // Timeout
    public static final int TIMEOUT = 60 * 1000; // milliseconds
    
    /****************************************************************************/

    // Action state
    private int state;
    
    // Search object as container for request and results
    private String[] search;
    
    private Search cont;
    
    // Last activity
    private long lastActivity = System.currentTimeMillis();
    
    // "-", "18-22", "23-29", "30-39", "40-49", "50-59", ">60"
    
    private final int[] ages = {
    	0, 99,
    	18, 22,
    	23, 29,
    	30, 39,
    	40, 49,
    	50, 59,
    	60, 99
    };
    
    
    public SearchAction(Search cont, String[] search, int _calledBy)
    {
    	super(false, true);
    	this.search = search;
    	this.cont = cont;
    }

    // Init action
    protected void init() throws JimmException
    {
    	ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    	
    	for (int i = search.length-1; i >= 0; i--) if (search[i] == null) search[i] = Options.emptyString;
    	
    		Util.writeWord(buffer, 0x5f05, true);
    		
    		// UIN
            if (search[Search.UIN].length() != 0)
            {
            	Util.writeWord(buffer, TLV_TYPE_UIN, true);
            	Util.writeWord(buffer, 0x0004, false);
            	Util.writeDWord(buffer, Integer.parseInt(search[Search.UIN]), false);
            }
    		
            // NICK
    		if (search[Search.NICK].length() != 0)
    			Util.writeAsciizTLV(TLV_TYPE_NICK, buffer, search[Search.NICK]);
    		
    		// First name
    		if (search[Search.FIRST_NAME].length() != 0)
    			Util.writeAsciizTLV(TLV_TYPE_FIRSTNAME, buffer, search[Search.FIRST_NAME]);
    		
    		// Last name
    		if (search[Search.LAST_NAME].length() != 0)
    			Util.writeAsciizTLV(TLV_TYPE_LASTNAME, buffer, search[Search.LAST_NAME]);
    		
    		// email
    		if (search[Search.EMAIL].length() != 0)
    			Util.writeAsciizTLV(TLV_TYPE_EMAIL, buffer, search[Search.EMAIL]);
    		
    		// City
    		if (search[Search.CITY].length() != 0)
    			Util.writeAsciizTLV(TLV_TYPE_CITY, buffer, search[Search.CITY]);
    		
    		// Keyword
    		if (search[Search.KEYWORD].length() != 0)
    			Util.writeAsciizTLV(TLV_TYPE_KEYWORD, buffer, search[Search.KEYWORD]);
    		
    		// Age (user enter age as "minAge-maxAge", "-maxAge", "minAge-" or "age")
    		int ageIndex = Util.strToIntDef(search[Search.AGE], 0);
    		if (ageIndex != 0)
    		{
    			Util.writeWord(buffer, 0x6801, true);
    			Util.writeWord(buffer, 4, false);
    			Util.writeWord(buffer, ages[2*ageIndex], false);
    			Util.writeWord(buffer, ages[2*ageIndex+1], false);
    		}
    		
    		
    		// Gender
    		int gender = Util.strToIntDef(search[Search.GENDER], 0);
    		if (gender != 0)
    		{
    			Util.writeWord(buffer, TLV_TYPE_GENDER, true);
    			Util.writeWord(buffer, 1, false);
    			Util.writeByte(buffer, gender);
    		}
    		
    		// Only online
    		Util.writeWord(buffer, TLV_TYPE_ONLYONLINE, true);
    		Util.writeWord(buffer, 1, false);
    		Util.writeByte(buffer, search[Search.ONLY_ONLINE].equals("1") ? 1 : 0);
    	
    	ToIcqSrvPacket packet = new ToIcqSrvPacket(SnacPacket.CLI_TOICQSRV_COMMAND,0x0002,Options.getString(Options.OPTION_UIN),0x07D0,new byte[0], buffer.toByteArray());
        Icq.c.sendPacket(packet);
        
        this.state = STATE_UIN_SEARCH_SENT;
    }
    

    // Forwards received packet, returns true if packet was consumed
    protected synchronized boolean forward(Packet packet) throws JimmException
    {
        // Flag indicates whether packet has been consumed or not
        boolean consumed = false;

        if (this.state == STATE_UIN_SEARCH_SENT || this.state == STATE_FIRSTRESULT_RECEIVED)
        {
            // Watch out for SRV_FROMICQSRV packet type
            if (packet instanceof FromIcqSrvPacket)
            {
                FromIcqSrvPacket fromIcqServerPacket = (FromIcqSrvPacket) packet;

                    int marker = 0;
                    
                    byte[] data = fromIcqServerPacket.getData();

                    if (Util.getWord(data,marker) == 0xa401)
                        this.state = STATE_FIRSTRESULT_RECEIVED;
                    if (Util.getWord(data,marker) == 0xae01)
                        this.state = STATE_LASTRESULT_RECEIVED;
                    
                    marker += 2;
                    if (Util.getByte(data,marker)== 0x0A)
                    {
                        // Get UIN
                        marker += 3;
                        long uin = Util.getDWord(data,marker,false);
                        
                        // Get nick
                        marker += 4;
                        
                        String[] strings = new String[4];
                        
                        // Get the strings
                        // #0 Nick
                        // #1 Firstname
                        // #2 Lastname
                        // #3 EMail
                        for (int i=0;i<4;i++)
                        {
                            strings[i] = Util.byteArrayToString(data,marker+2,Util.getWord(data,marker,false));
                            marker += 2+Util.getWord(data,marker,false);
                        }
                        
                        // Get auth flag
                        String auth = (Util.getByte(data,marker) == 0) ? "1" : "0";
                        marker += 1;
                        
                        // Get status
                        int status = Util.getWord(data,marker,false);
                        marker += 2;
                        
                        // Get gender
                        String gender = Util.genderToString( Util.getByte(data,marker) );
                        marker += 1;
                        
                        // Get age
                        int age = Util.getWord(data,marker,false);
                        
                        cont.addResult(String.valueOf(uin),strings[0],strings[1]+" "+strings[2],strings[3],auth,status,gender,age);
                        
                        if (this.state == STATE_LASTRESULT_RECEIVED)
                        {
                            marker += 2;
                            long foundleft = Util.getDWord(data,marker,false);
                            // System.out.println("foundleft: "+foundleft);
                            this.state = STATE_SEARCH_FINISHED;
                        }
                    }
                    else
                    {
                        this.state = ConnectAction.STATE_ERROR;
                    }
                }
            }
        
        // Update activity timestamp
        this.lastActivity = System.currentTimeMillis();
        
        return consumed;
    }
    
    public void onEvent(int eventTuype)
    {
    	switch (eventTuype)
    	{
    	case ON_COMPLETE:
    		cont.getSearchForm().activate(Search.SearchForm.ACTIV_SHOW_RESULTS);
    		break;
    		
    	case ON_ERROR:
            if (this.state == STATE_FIRSTRESULT_RECEIVED)
            {
            	JimmException.handleException(new JimmException(159, 0, true));
            }
            else
            {
            	cont.getSearchForm().activate(Search.SearchForm.ACTIV_SHOW_NORESULTS);
            }
    		break;
    		
    	case ON_CANCEL:
    		cont.getSearchForm().activate(Search.SearchForm.ACTIV_JUST_SHOW);
    		state = STATE_SEARCH_CANCELED;
    		break;
    	}
    }
    
    // Returns true if the action is completed
    public boolean isCompleted()
    {
        return (state == STATE_SEARCH_FINISHED) ||
               (state == STATE_SEARCH_CANCELED);
    }

    // Returns true if an error has occured
    public synchronized boolean isError()
    {
        return (state == ConnectAction.STATE_ERROR) || 
        		((lastActivity+SearchAction.TIMEOUT) < System.currentTimeMillis());
    }
}
