package com.bao.lc.site.s3.commands; import java.net.URI; import java.util.ArrayList; import java.util.List; import org.apache.commons.chain.Context; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.NameValuePair; import org.htmlparser.NodeFilter; import org.htmlparser.Parser; import org.htmlparser.Tag; import org.htmlparser.filters.AndFilter; import org.htmlparser.filters.HasAttributeFilter; import org.htmlparser.filters.NodeClassFilter; import org.htmlparser.tags.FormTag; import org.htmlparser.tags.InputTag; import org.htmlparser.tags.OptionTag; import org.htmlparser.tags.SelectTag; import org.htmlparser.util.NodeList; import org.htmlparser.util.ParserException; import com.bao.lc.ResMgr; import com.bao.lc.bean.IDValuePair; import com.bao.lc.bean.ResultCode; import com.bao.lc.client.ParamListBuilder; import com.bao.lc.client.RequestBuilder; import com.bao.lc.httpcommand.AbstractCommand; import com.bao.lc.httpcommand.params.HttpCommandPNames; import com.bao.lc.httpcommand.params.HttpCommandParams; import com.bao.lc.site.RandCodeBuilder; import com.bao.lc.site.s3.TdUtils; import com.bao.lc.site.s3.bean.GenericBean; import com.bao.lc.site.s3.bean.PassengerInfo; import com.bao.lc.site.s3.bean.TrainTicketInfo; import com.bao.lc.site.s3.gui.GUIUtils; import com.bao.lc.site.s3.params.TdPNames; import com.bao.lc.site.s3.params.TdParams; public class ParseSubmitOrderPage extends AbstractCommand { private static Log log = LogFactory.getLog(ParseSubmitOrderPage.class); private static final int MAX_PASSENGER_COUNT = 5; @Override protected IDValuePair preExecute(Context context) throws Exception { return ResultCode.RC_OK; } @Override protected IDValuePair doExecute(Context context) throws Exception { return ResultCode.RC_OK; } @Override protected IDValuePair postExecute(Context context) throws Exception { String submitOrderPage = MapUtils.getString(context, TdPNames._CONFIRM_PASSENGER_CONTENT); String charset = MapUtils.getString(context, TdPNames._CONFIRM_PASSENGER_ENCODING); if(submitOrderPage == null || charset == null) { log.fatal("Assert failure: submitOrderPage or(and) charset is null"); return ResultCode.RC_ASSERT_FAILURE; } return buildNextRequest(context, submitOrderPage, charset); } private IDValuePair buildNextRequest(Context context, String submitOrderPage, String charset) throws ParserException { FormTag form = getSubmitForm(submitOrderPage, charset); if(form == null) { return ResultCode.RC_ASSERT_FAILURE; } String randCode = MapUtils.getString(context, TdPNames._CONFIRM_PASSENGER_VOCDE); if(randCode == null) { randCode = getRandCode(context, submitOrderPage, charset); } if(randCode == null) { TdParams.getUI(context).info(ResMgr.getString("td.msg.vcode.input.null")); return ResultCode.RC_INPUT_NULL_VCODE; } context.put(TdPNames._CONFIRM_PASSENGER_VOCDE, randCode); ParamListBuilder pb = new ParamListBuilder(); getNonPassengerParams(context, form, randCode, pb); getPassengerParams(submitOrderPage, charset, context, pb); List<NameValuePair> paramList = pb.build(); if(log.isDebugEnabled()) { log.debug("confirm parameters: " + paramList); } RequestBuilder rb = new RequestBuilder(); URI baseURI = HttpCommandParams.getTargetRequestURI(context); rb.method(form.getFormMethod()).baseURI(baseURI).reference(form.getFormLocation()); rb.paramList(paramList).encoding(charset); context.put(HttpCommandPNames.TARGET_REQUEST, rb.create()); context.put(HttpCommandPNames.TARGET_REFERER, baseURI.toString()); return ResultCode.RC_OK; } private FormTag getSubmitForm(String submitOrderPage, String charset) throws ParserException { Parser myParser = Parser.createParser(submitOrderPage, charset); NodeFilter[] a = new NodeFilter[0]; List<NodeFilter> filters = new ArrayList<NodeFilter>(); filters.add(new NodeClassFilter(FormTag.class)); filters.add(new HasAttributeFilter("id", "confirmPassenger")); filters.add(new HasAttributeFilter("name", "save_passenger_single")); NodeFilter filter = new AndFilter(filters.toArray(a)); NodeList nodeList = myParser.parse(filter); if(nodeList.size() <= 0) { log.error("Can't find the target form. id=confirmPassenger"); return null; } FormTag form = (FormTag) nodeList.elementAt(0); return form; } private String getRandCode(Context context, String submitOrderPage, String charset) throws ParserException { Parser myParser = Parser.createParser(submitOrderPage, charset); NodeFilter[] a = new NodeFilter[0]; List<NodeFilter> filters = new ArrayList<NodeFilter>(); filters.add(new NodeClassFilter(Tag.class)); filters.add(new HasAttributeFilter("id", "img_rrand_code")); filters.add(new HasAttributeFilter("src")); NodeFilter filter = new AndFilter(filters.toArray(a)); NodeList nodeList = myParser.parse(filter); if(nodeList.size() <= 0) { log.error("Can't find the img_rrand_code node."); return null; } Tag randCodeTag = (Tag) nodeList.elementAt(0); String location = randCodeTag.getAttribute("src"); RequestBuilder rb = new RequestBuilder(); URI baseURI = HttpCommandParams.getTargetRequestURI(context); rb.baseURI(baseURI).reference(location).encoding(charset); RandCodeBuilder rcb = new RandCodeBuilder(); rcb.context(context).request(rb.create()).referer(baseURI.toString()); rcb.prompt(ResMgr.getString("td.rand.code.input")).parent(GUIUtils.getMainFrame()); return rcb.build(); } private void getNonPassengerParams(Context context, FormTag form, String randCode, ParamListBuilder pb) { TrainTicketInfo ticketInfo = TdParams.getOrderTicketInfo(context); NodeList inputs = form.getFormInputs(); for(int i = 0, size = inputs.size(); i < size; i++) { InputTag input = (InputTag) inputs.elementAt(i); String name = input.getAttribute("name"); if(name == null) { log.debug("null name input in form [confirmPassenger], raw: " + input.toHtml()); continue; } if(StringUtils.containsIgnoreCase(name, "passenger")) { continue; } if(StringUtils.containsIgnoreCase(name, "checkbox")) { continue; } String type = input.getAttribute("type"); if("radio".equals(type)) { String checked = input.getAttribute("checked"); if(!"checked".equals(checked)) { continue; } } String value = input.getAttribute("value"); if(name.equals("orderRequest.train_date")) { value = MapUtils.getString(context, TdPNames.PARAM_TICKET_DATE); } else if(name.equals("orderRequest.start_time")) { value = ticketInfo.getStartTime(); } else if(name.equals("orderRequest.end_time")) { value = ticketInfo.getEndTime(); } else if(name.equals("randCode")) { value = randCode; } pb.append(name, value); } } private IDValuePair getPassengerParams(String submitOrderPage, String charset, Context context, ParamListBuilder pb) { List<PassengerInfo> passengers = TdParams.getPassengerList(context); for(int i = 0, size = passengers.size(); i < size; i++) { int index = i + 1; PassengerInfo passenger = passengers.get(i); // checkbox i pb.append("checkbox" + i, String.valueOf(i)); // passengerTickets pb.append("passengerTickets", passenger.getPassengerTickets()); // old passengers pb.append("oldPassengers", passenger.getOldPassenger()); // passenger filed info String seatClassValue = passenger.seatClass; String similarSeatClass = getPassengerSeat(submitOrderPage, charset, seatClassValue, index); if(similarSeatClass != null) { seatClassValue = similarSeatClass; } pb.append("passenger_" + index + "_seat", seatClassValue); pb.append("passenger_" + index + "_ticket", passenger.tiketType); pb.append("passenger_" + index + "_name", passenger.name); pb.append("passenger_" + index + "_cardtype", passenger.cardType); pb.append("passenger_" + index + "_cardno", passenger.cardNo); pb.append("passenger_" + index + "_mobileno", passenger.phone); // save? pb.append("checkbox9", passenger.isSave); } for(int i = passengers.size(); i < MAX_PASSENGER_COUNT; i++) { pb.append("oldPassengers", ""); pb.append("checkbox9", "Y"); } return ResultCode.RC_OK; } private SelectTag getSeatSelect(String submitOrderPage, String charset, int index) throws ParserException { Parser myParser = Parser.createParser(submitOrderPage, charset); NodeFilter[] a = new NodeFilter[0]; List<NodeFilter> filters = new ArrayList<NodeFilter>(); filters.add(new NodeClassFilter(SelectTag.class)); filters.add(new HasAttributeFilter("id", "passenger_" + index + "_seat")); NodeFilter filter = new AndFilter(filters.toArray(a)); NodeList nodeList = myParser.parse(filter); if(nodeList.size() <= 0) { log.error("Can't find the target form. id=passenger_" + index + "_seat"); return null; } SelectTag seatSelect = (SelectTag) nodeList.elementAt(0); return seatSelect; } private String getPassengerSeat(String submitOrderPage, String charset, String rawSeat, int index) { SelectTag seatSelect = null; try { seatSelect = getSeatSelect(submitOrderPage, charset, index); } catch(ParserException e) { log.error("Can't find the seat select tag.", e); return null; } if(seatSelect == null) { return null; } String seatName = GenericBean.getField(rawSeat, 2, 1, TdUtils.getSeatClasses()); OptionTag[] options = seatSelect.getOptionTags(); for(OptionTag option : options) { //Hit in our config file. if(seatName.equals(option.getOptionText())) { return null; } } StringBuilder sb = new StringBuilder(); sb.append("seatName=").append(seatName); sb.append(",rawSeat=").append(rawSeat).append(". "); for(OptionTag option : options) { sb.append("option=").append(option.getOptionText()).append(",").append(option.getValue()).append(" "); } log.info("Can't find the exactly matched seat. Try to find a similar one. " + sb.toString()); // Errrrr..., no hit, try to find the best matched for(OptionTag option : options) { String optionText = option.getOptionText(); if(seatName.length() >= 2 && optionText.length() >= 2) { // Found the similar seat if(seatName.regionMatches(0, optionText, 0, 2)) { log.info("Find the most similar requried seat. seatName=" + seatName + ", optionText=" + optionText + ", optionValue=" + option.getValue()); return option.getValue(); } } } log.error("Can't find the similar matched seat. "); return null; } }