package jp.sourceforge.shovel.mobilephone.impl;

import static java.util.regex.Pattern.*;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import jp.sourceforge.shovel.exception.ApplicationException;
import jp.sourceforge.shovel.mobilephone.ISoftBank;

public class SoftBankImpl extends AbstractMobilePhoneImpl implements ISoftBank {
    boolean packetCompliant_;
    String serialNumber_;
    String vendor_;
    String vendorVersion_;
    Map<String, String> javaInfo_;
    boolean type3G_;
    String msname_;
    final static Map<String, String> images_;
    static {
        images_ = new HashMap<String, String>();
        images_.put("1","&#xE21C;");
        images_.put("2","&#xE21D;");
        images_.put("3","&#xE21E;");
        images_.put("4","&#xE21F;");
        images_.put("5","&#xE220;");
        images_.put("6","&#xE221;");
        images_.put("7","&#xE222;");
        images_.put("8","&#xE223;");
        images_.put("9","&#xE224;");
        images_.put("0","&#xE225;");
        images_.put("#","&#xE210;");
    }
    
    public boolean isJPhone() {
        return isSoftBank();
    }
    public boolean isVodafone() {
        return isSoftBank();
    }
    public boolean isPacketCompliant() {
        return packetCompliant_;
    }
    public String getSerialNumber() {
        return serialNumber_;
    }
    public String getVendor() {
        return vendor_;
    }
    public String getVendorVersion() {
        return vendorVersion_;
    }
    public String getProfile() {
        return javaInfo_.get("Profile");
    }
    public String getConfiguration() {
        return javaInfo_.get("Configuration");
    }
    String getExtProfile() {
        return javaInfo_.get("Ext-Profile");
    }
    public String getExtJProfile() {
        if (javaInfo_.get("Ext-J-Profile") == null) {
            return getExtProfile();
        }
        return javaInfo_.get("Ext-J-Profile");
    }
    public String getExtVProfile() {
        return javaInfo_.get("Ext-V-Profile");
    }
    public String getCarrierShortName() {
        return "S";
    }
    public String getCarrierLongName() {
        return "SoftBank";
    }
    public boolean isTypeC() {
        return !type3G_ && version_.matches("^[32]\\.\\d$");
    }
    public boolean isTypeP() {
        return !type3G_ && version_.matches("^4\\.\\d$");
    }
    public boolean isTypeW() {
        return !type3G_ && version_.matches("^5\\.\\d$");
    }
    public boolean isType3GC() {
        return type3G_;
    }
    public String getMsname() {
        return msname_;
    }
    public boolean isSoftBank() {
        return true;
    }
    public String getUID() {
        return getRequest().getHeader("X-JPHONE-UID");
    }
    public Map<String, String> getNumberImages() {
        return images_;
    }
    
    enum CarrierType {
        UNKNOWN     ("unknown"),
        SOFTBANK    ("SoftBank"),
        SEMULATOR   ("Semulator"),
        VODAFONE    ("Vodafone"),
        VEMULATOR   ("Vemulator"),
        J_PHONE     ("J-PHONE"),
        J_EMULATOR  ("J-EMULATOR"),
        MOTOROLA    ("MOT-"),
        MOTEMULATOR ("MOTEMULATOR");
        
        String id_;
        CarrierType(String id) {
            id_ = id;
        }
        String getId() {
            return id_;
        }
        
        static CarrierType find(String id) {
            for (CarrierType carrierType : values()) {
                if (carrierType.getId().compareTo(id) == 0) {
                    return carrierType;
                }
            }
            return UNKNOWN;
        }
    }
    
    @Override
    void parse() throws ApplicationException {
        String[] tokens =  getUserAgent().split(" ");
        if (tokens == null || tokens.length <= 0) {
            throw new ApplicationException("");
        }
        
        Pattern pattern = Pattern.compile("^(?:(SoftBank|Semulator|Vodafone|Vemulator|J-PHONE|J-EMULATOR)/\\d\\.\\d|MOT-|MOTEMULATOR)");
        Matcher matcher = pattern.matcher(tokens[0]);
        String carrier = "Motorola";
        if (matcher.find()) {
            if (matcher.groupCount() > 0) {
                carrier = matcher.group(1);
                if (carrier == null) {
                    carrier = matcher.group(0);
                }
            }
        }
        
        type3G_ = true;
        javaInfo_ = new HashMap<String, String>();
        switch (CarrierType.find(carrier)) {
        case SOFTBANK:
        case SEMULATOR:
        case VODAFONE:
        case VEMULATOR:
            parseVodafone(tokens);
            break;
        case J_PHONE:
        case J_EMULATOR:
            parseJPhone(tokens);
            break;
        case MOTOROLA:
        case MOTEMULATOR:
            parseMotorola(tokens);
            break;
        default:
            throw new ApplicationException("");
        }
        makeScreenInfo();
        msname_ = getRequest().getHeader("X-JPHONE-MSNAME");
    }
    
    void parseVodafone(String[] userAgent) throws ApplicationException {
        packetCompliant_ = true;
        String[] tokens = userAgent[0].split("/");
        if (tokens == null || tokens.length < 3) {
            throw new ApplicationException("");
        }
        name_ = tokens[0];
        version_ = tokens[1];
        rawModel_ = tokens[2];
        if (tokens.length > 4 && tokens[4] != null && tokens[4].length() > 0) {
            Pattern pattern = Pattern.compile("^SN(.+)");
            Matcher matcher = pattern.matcher(tokens[4]);
            if (matcher.find()) {
                serialNumber_ = matcher.group(1);
            }
        }
        
        Pattern pattern = Pattern.compile("^([a-z]+)((?:[a-z]|\\d){4})", CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(tokens[3]);
        if (!matcher.find()) {
            throw new ApplicationException("");
        }
        
        vendor_ = matcher.group(1);
        vendorVersion_ = matcher.group(2);
        
        for (int i = 2; i < userAgent.length; i++) {
            tokens = userAgent[i].split("/");
            if (tokens != null && tokens.length == 2) {
                javaInfo_.put(tokens[0], tokens[1]);
            }
        }
    }
    
    void parseJPhone(String[] userAgent) throws ApplicationException {
        type3G_ = false;
        String[] tokens = userAgent[0].split("/");
        if (tokens == null || tokens.length < 3) {
            throw new ApplicationException("");
        }
        name_ = tokens[0];
        version_ = tokens[1];
        rawModel_ = tokens[2];
        if (tokens.length > 3 && tokens[3] != null && tokens[3].length() > 0) {
            Pattern pattern = Pattern.compile("^SN(.+)");
            Matcher matcher = pattern.matcher(tokens[3]);
            if (!matcher.find()) {
                throw new ApplicationException("");
            }
            serialNumber_ = matcher.group(1);
        }
        if (userAgent.length > 1) {
            //J-PHONE/4.0/J-SH51/SNJSHA3029293 SH/0001aa Profile/MIDP-1.0 Configuration/CLDC-1.0 Ext-Profile/JSCL-1.1.0
            packetCompliant_ = true;
            tokens = userAgent[1].split("/");
            if (tokens == null || tokens.length < 2) {
                throw new ApplicationException("");
            }
            
            vendor_ = tokens[0];
            vendorVersion_ = tokens[1];
            
            for (int i = 2; i < userAgent.length; i++) {
                tokens = userAgent[i].split("/");
                if (tokens == null || tokens.length < 2) {
                    throw new ApplicationException("");
                }
                javaInfo_.put(tokens[0], tokens[1]);
            }
        } else {
            //J-PHONE/2.0/J-DN02
            if (rawModel_ != null && rawModel_.length() > 0) {
                Pattern pattern = Pattern.compile("V\\d+([A-Z]+)");
                Matcher matcher = pattern.matcher(rawModel_);
                if (matcher.find()) {
                    vendor_ = matcher.group(1);
                }
                pattern = Pattern.compile("J-([A-Z]+)");
                matcher = pattern.matcher(rawModel_);
                if (matcher.find()) {
                    vendor_ = matcher.group(1);
                }
            }
        }
    }
    
    void parseMotorola(String[] userAgent) throws ApplicationException {
        packetCompliant_ = true;
        vendor_ = "MOT";
        String[] tokens = userAgent[0].split("/");
        rawModel_ = tokens[0];
        vendorVersion_ = tokens[1];
        if (rawModel_.compareTo("MOT-C980") == 0) {
            model_ = "V702sMO";
        } else if (rawModel_.compareTo("MOT-V980") == 0) {
            model_ = "V702MO";
        } else {
            throw new ApplicationException("");
        }
        
        for (int i = 2; i < userAgent.length; i++) {
            tokens = userAgent[i].split("/");
            javaInfo_.put(tokens[0], tokens[1]);
        }
    }
    
    int width_;
    int height_;
    int depth_;
    boolean color_;
    
    public int getWidth() {
        return width_;
    }
    public int getHeight() {
        return height_;
    }
    public int getDepth() {
        return depth_;
    }
    public boolean isColor() {
        return color_;
    }
    void makeScreenInfo() {
        String header = getRequest().getHeader("X-JPHONE-DISPLAY");
        if (header != null && header.length() > 0) {
            String[] tokens = header.split("\\*");
            width_ = Integer.parseInt(tokens[0]);
            height_ = Integer.parseInt(tokens[1]);
        }
        header = getRequest().getHeader("X-JPHONE-COLOR");
        if (header != null && header.length() > 0) {
            Pattern pattern = Pattern.compile("^([CG])(\\d+)$");
            Matcher matcher = pattern.matcher(header);
            if (matcher.matches()) {
                color_ = matcher.group(1).compareTo("C") == 0;
                depth_ = Integer.parseInt(matcher.group(2));
            }
        }
    }
}
