package jp.sourceforge.shovel.mobilephone.impl;

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import jp.sourceforge.shovel.dao.IDoCoMoExtendDao;
import jp.sourceforge.shovel.entity.IDoCoMoExtend;
import jp.sourceforge.shovel.exception.ApplicationException;
import jp.sourceforge.shovel.mobilephone.IDoCoMo;
import jp.sourceforge.shovel.mobilephone.impl.AbstractMobilePhoneImpl;

public class DoCoMoImpl extends AbstractMobilePhoneImpl implements IDoCoMo {
    boolean foma_;
    String comment_;
    int cacheSize_;
    String serialNumber_;
    String status_;
    int bandWidth_;
    String cardID_;
    IDoCoMoExtend extend_;
    int widthBytes_;
    int heightBytes_;
    
    final static Set<String> gpsModels_;
    final static Map<String, String> images_;

    static {
        gpsModels_ = new HashSet<String>();
        gpsModels_.addAll(Arrays.asList(
            "N02A",   "SH01A",  "SH02A",  "SH03A",  "SH04A",
            "F05A",   "F06A",   "P01A",   "P02A",   "N01A",
            "F906i",   "N906i",   "N906iL",  "F01A",   "F03A",
            "P906i",   "SO906i",  "SH906i",  "SH906i",  "N906imyu",
            "F884i",   "F801i",   "F905iBiz","SO905iCS","N905iBiz",
            "N905imyu","SO905i",  "F905i",   "P905i",   "N905i",
            "D905i",   "SH905i",  "P904i",   "D904i",   "F904i",
            "N904i",   "SH904i",  "F883iESS","F883iES", "F903iBSC",
            "SO903i",  "F903i",   "D903i",   "N903i",   "P903i",
            "SH903i",  "SA800i",  "SA702i",  "SA700iS", "F505iGPS",
            "F661i"
        ));
        images_ = new HashMap<String, String>();
        images_.put("1","&#xE6E2;");
        images_.put("2","&#xE6E3;");
        images_.put("3","&#xE6E4;");
        images_.put("4","&#xE6E5;");
        images_.put("5","&#xE6E6;");
        images_.put("6","&#xE6E7;");
        images_.put("7","&#xE6E8;");
        images_.put("8","&#xE6E9;");
        images_.put("9","&#xE6EA;");
        images_.put("0","&#xE6EB;");
        images_.put("#","&#xE6E0;");
    }
    
    public DoCoMoImpl() {
    }
    @Override
    public boolean isDoCoMo() {
        return true;
    }
    @Override
    void parse() throws ApplicationException {
        String userAgent = getUserAgent();
        String[] tokens = userAgent.split(" ", 2);
        if (tokens == null || tokens.length <= 0) {
            throw new ApplicationException("");
        }
        
        if (tokens != null && tokens.length == 2) {
            String main = tokens[0];
            String fomaOrComment = tokens[1];
            
            Pattern pattern = Pattern.compile("^\\((.*)\\)");
            Matcher matcher = pattern.matcher(fomaOrComment);
            if (matcher.find()) {
                comment_ = matcher.group(1);
                parseMain(main);
            } else {
                foma_ = true;
                tokens = main.split("/");
                if (tokens.length != 2) {
                    throw new ApplicationException("");
                }
                name_ = tokens[0];
                version_ = tokens[1];
                parseFOMA(fomaOrComment);
            }
        } else {
            parseMain(userAgent);
        }
        makeScreenInfo();
    }
    public String getHTMLVersion() {
        return extend_.getHtmlVersion();
    }
    public int getCacheSize() {
        if (cacheSize_ > 0) {
            return cacheSize_;
        }
        return 5;
    }
    public String getSeries() {
        Pattern pattern = Pattern.compile("(\\d{4})");
        Matcher matcher = pattern.matcher(rawModel_);
        if (matcher.find()) {
            return "FOMA";
        }
        pattern = Pattern.compile("(\\d{3}i)");
        matcher = pattern.matcher(rawModel_);
        if (matcher.find()) {
            return matcher.group(1);
        }
        pattern = Pattern.compile("(\\d{2}[A-Z])");
        matcher = pattern.matcher(rawModel_);
        if (matcher.find()) {
            return matcher.group(1);
        }
        if (rawModel_.compareTo("P651ps") == 0) {
            return "651";
        }
        return null;
    }
    public String getVendor() {
        Pattern pattern = Pattern.compile("([A-Z]+)\\d");
        Matcher matcher = pattern.matcher(rawModel_);
        if (matcher.find()) {
            return matcher.group(1);
        }
        return null;
    }
    public String getStatus() {
        return status_;
    }
    public int getBandWidth() {
        return bandWidth_;
    }
    public String getSerialNumber() {
        return serialNumber_;
    }
    public boolean isFOMA() {
        return foma_;
    }
    public String getComment() {
        return comment_;
    }
    public String getCardID() {
        return cardID_;
    }
    public boolean isGPS() {
        return gpsModels_.contains(rawModel_);
    }
    @Override
    public String getCarrierShortName() {
        return "I";
    }
    @Override
    public String getCarrierLongName() {
        return "DoCoMo";
    }
    @Override
    public String getUID() {
        return getRequest().getHeader("X-DCMGUID");
    }
    @Override
    public int getWidth() {
        if (extend_ == null) {
            return super.getWidth();
        }
        return extend_.getWidth();
    }
    @Override
    public int getHeight() {
        if (extend_ == null) {
            return super.getHeight();
        }
        return extend_.getHeight();
    }
    @Override
    public int getDepth() {
        if (extend_ == null) {
            return super.getDepth();
        }
        return extend_.getDepth();
    }
    @Override
    public boolean isColor() {
        if (extend_ == null) {
            return super.isColor();
        }
        return getDepth() > 1;
    }
    @Override
    public int getWidthBytes() {
        if (extend_ == null) {
            return super.getWidthBytes();
        }
        return widthBytes_;
    }
    @Override
    public int getHeightBytes() {
        if (extend_ == null) {
            return super.getHeightBytes();
        }
        return heightBytes_;
    }
    public Map<String, String> getNumberImages() {
        return images_;
    }
    
    IDoCoMoExtendDao getDoCoMoExtendDao() {
        return (IDoCoMoExtendDao)getContainer().getComponent(IDoCoMoExtendDao.class);
    }
    
    void parseMain(String main) throws ApplicationException {
        if (main == null || main.length() <= 0) {
            throw new ApplicationException("");
        }
        String[] tokens = main.split("/", 5);
        if (tokens == null || tokens.length < 3) {
            throw new ApplicationException("");
        }
        name_ = tokens[0];
        version_ = tokens[1];
        rawModel_ = tokens[2];
        
        if (rawModel_.compareTo("SH505i2") == 0) {
            model_ = "SH505i";
        } else if (rawModel_.compareTo("N506iS2") == 0) {
            model_ = "N506iSII";
        } else if (rawModel_.compareTo("P506iC2") == 0) {
            model_ = "P506iCII";
        }
        
        if (tokens.length >= 4) {
            Pattern pattern = Pattern.compile("^c(\\d+)$");
            Matcher matcher = pattern.matcher(tokens[3]);
            if (!matcher.find()) {
                throw new ApplicationException("");
            }
            cacheSize_ = Integer.parseInt(matcher.group(1));
        }
        
        if (tokens.length >= 5) {
            String[] rest = tokens[4].split("/");
            if (rest == null || rest.length <= 0) {
                throw new ApplicationException("");
            }
            for (String value : rest) {
                Pattern pattern = Pattern.compile("^ser(\\w{11})$");
                Matcher matcher = pattern.matcher(value);
                if (matcher.find()) {
                    serialNumber_ = matcher.group(1);
                    continue;
                }
                pattern = Pattern.compile("^([ST][CDBJ])$");
                matcher = pattern.matcher(value);
                if (matcher.find()) {
                    status_ = matcher.group(1);
                    continue;
                }
                pattern = Pattern.compile("^s(\\d+)$");
                matcher = pattern.matcher(value);
                if (matcher.find()) {
                    bandWidth_ = Integer.parseInt(matcher.group(1));
                }
                pattern = Pattern.compile("^W(\\d+)H(\\d+)$");
                matcher = pattern.matcher(value);
                if (matcher.find()) {
                    widthBytes_ = Integer.parseInt(matcher.group(1));
                    heightBytes_ = Integer.parseInt(matcher.group(2));
                }
            }
        }
    }
    void parseFOMA(String foma) throws ApplicationException {
        Pattern pattern = Pattern.compile("^([^(\\s]+)");
        Matcher matcher = pattern.matcher(foma);
        if (!matcher.find()) {
            throw new ApplicationException("");
        }
        rawModel_ = matcher.group(1);
        if (rawModel_.compareTo("MST_v_SH2101V") == 0) {
            rawModel_ = "SH2101V";
        } else if (rawModel_.compareTo("SH705i2") == 0) {
            model_ = "SH705iII";
        } else if (rawModel_.compareTo("N706i2") == 0) {
            model_ = "N706iII";
        }
        pattern = Pattern.compile("^([A-Z]+)(\\d{2}[A-Z])$");
        matcher = pattern.matcher(rawModel_);
        if (matcher.find()) {
            model_ = matcher.group(1) + "-" + matcher.group(2);
        }
        pattern = Pattern.compile("^[^(\\s]+\\s?\\(([^)]+)\\)(?:\\(([^)]+)\\))?$");
        matcher = pattern.matcher(foma);
        if (matcher.find()) {
            if (matcher.group(1).startsWith("compatible")) {
                comment_ = matcher.group(1);
                return;
            }
            if (matcher.groupCount() == 2) {
                //先方参照だから？空のことがある
                if (matcher.group(2) != null) {
                    if (matcher.group(2).startsWith("compatible")) {
                        comment_ = matcher.group(2);
                    }
                }
            }
            String[] rest = matcher.group(1).split(";");
            if (rest == null || rest.length <= 0) {
                throw new ApplicationException("");
            }
            for (String value : rest) {
                pattern = Pattern.compile("^c(\\d+)$");
                matcher = pattern.matcher(value);
                if (matcher.find()) {
                    cacheSize_ = Integer.parseInt(matcher.group(1));
                    continue;
                }
                pattern = Pattern.compile("^ser(\\w{15})$");
                matcher = pattern.matcher(value);
                if (matcher.find()) {
                    serialNumber_ = matcher.group(1);
                    continue;
                }
                pattern = Pattern.compile("^([TS][CDBJ])$");
                matcher = pattern.matcher(value);
                if (matcher.find()) {
                    status_ = matcher.group(1);
                    continue;
                }
                pattern = Pattern.compile("^icc(\\w{20})?$");
                matcher = pattern.matcher(value);
                if (matcher.find()) {
                    if (matcher.groupCount() == 1) {
                        cardID_ = matcher.group(1);
                    }
                    continue;
                }
                pattern = Pattern.compile("^W(\\d+)H(\\d+)$");
                matcher = pattern.matcher(value);
                if (matcher.find()) {
                    widthBytes_ = Integer.parseInt(matcher.group(1));
                    heightBytes_ = Integer.parseInt(matcher.group(2));
                    continue;
                }
                throw new ApplicationException("");
            }
        }
    }
    void makeScreenInfo() {
        IDoCoMoExtend extend = getDoCoMoExtendDao().find(getModel());
        if (extend != null) {
            extend_ = extend;
        }
    }
}
