package com.planet_ink.coffee_mud.Libraries; import com.planet_ink.coffee_mud.core.interfaces.*; import com.planet_ink.coffee_mud.core.*; import com.planet_ink.coffee_mud.core.collections.*; import com.planet_ink.coffee_mud.Abilities.interfaces.*; import com.planet_ink.coffee_mud.Areas.interfaces.*; import com.planet_ink.coffee_mud.Behaviors.interfaces.*; import com.planet_ink.coffee_mud.CharClasses.interfaces.*; import com.planet_ink.coffee_mud.Commands.interfaces.*; import com.planet_ink.coffee_mud.Common.DefaultPoll; import com.planet_ink.coffee_mud.Common.interfaces.*; import com.planet_ink.coffee_mud.Exits.interfaces.*; import com.planet_ink.coffee_mud.Items.interfaces.*; import com.planet_ink.coffee_mud.Locales.interfaces.*; import com.planet_ink.coffee_mud.MOBS.interfaces.*; import com.planet_ink.coffee_mud.Races.interfaces.*; import java.io.IOException; import java.util.*; import com.planet_ink.coffee_mud.Libraries.interfaces.*; import com.planet_ink.coffee_mud.Libraries.interfaces.XMLLibrary.XMLTag; /* Copyright 2005-2016 Bo Zimmerman 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. */ public class Polls extends StdLibrary implements PollManager { @Override public String ID(){return "Polls";} public SVector<Poll> pollCache=null; @Override public boolean shutdown() { pollCache=null; return true; } @Override public void addPoll(Poll P) { if (getCache() != null) getCache().add(P); } @Override public void removePoll(Poll P) { if (getCache() != null) getCache().remove(P); } public synchronized List<Poll> getCache() { if(CMSecurity.isDisabled(CMSecurity.DisFlag.POLLCACHE)) return null; if(pollCache==null) { pollCache=new SVector<Poll>(); final List<DatabaseEngine.PollData> list=CMLib.database().DBReadPollList(); Poll P=null; for(final DatabaseEngine.PollData data : list) { P=loadPollByName(data.name()); if(P!=null) pollCache.addElement(P); } } return pollCache; } @Override public Poll getPoll(String named) { final List<Poll> V=getCache(); if(V!=null) { for(final Poll P : V) if(P.getName().equalsIgnoreCase(named)) return P; } else { final Poll P=loadPollByName(named); return P; } return null; } @Override public Poll getPoll(int x) { final Iterator<Poll> p=getPollList(); Poll P=null; for(int i=0;i<=x;i++) { if(!p.hasNext()) return null; P=p.next(); } return P; } @Override @SuppressWarnings("unchecked") public List<Poll>[] getMyPollTypes(MOB mob, boolean login) { final Iterator<Poll> i=getPollList(); final List<Poll> list[]=new List[3]; for(int l=0;l<3;l++) list[l]=new Vector<Poll>(); for(;i.hasNext();) { final Poll P = i.next(); if(loadPollIfNecessary(P)) { if((P.mayIVote(mob))&&(login)&&(CMath.bset(P.getFlags(),Poll.FLAG_NOTATLOGIN))) list[1].add(P); else if(P.mayIVote(mob)) list[0].add(P); else if(P.mayISeeResults(mob)) list[2].add(P); } } return list; } @Override public Iterator<Poll> getPollList() { final List<Poll> L=getCache(); if(L!=null) return L.iterator(); final List<DatabaseEngine.PollData> V=CMLib.database().DBReadPollList(); final List<Poll> list=new Vector<Poll>(); for(final DatabaseEngine.PollData data : V) { final Poll P=(Poll)CMClass.getCommon("DefaultPoll"); P.setName(data.name()); P.setFlags(data.flag()); P.setQualZapper(data.qual()); P.setExpiration(data.expiration()); P.setLoaded(false); list.add(P); } return list.iterator(); } @Override public void processVote(Poll P, MOB mob) { if(!P.mayIVote(mob)) return; try { if(!loadPollIfNecessary(P)) return; final StringBuffer present=new StringBuffer(""); present.append("^O"+P.getDescription()+"^N\n\r\n\r"); if(P.getOptions().size()==0) { mob.tell(L("@x1Oops! No options defined!",present.toString())); return; } Poll.PollOption PO=null; for(int o=0;o<P.getOptions().size();o++) { PO=P.getOptions().get(o); present.append("^H"+CMStrings.padLeft(""+(o+1),2)+": ^N"+PO.text+"\n\r"); } if(CMath.bset(P.getFlags(),Poll.FLAG_ABSTAIN)) present.append("^H : ^NPress ENTER to abstain from voting.^?\n\r"); mob.tell(present.toString()); int choice=-1; while((choice<0)&&(mob.session()!=null)&&(!mob.session().isStopped())) { final String s=mob.session().prompt(L("Please make your selection (1-@x1): ",""+P.getOptions().size())); if((s.length()==0)&&(CMath.bset(P.getFlags(),Poll.FLAG_ABSTAIN))) break; if(CMath.isInteger(s)&&(CMath.s_int(s)>=1)&&(CMath.s_int(s)<=P.getOptions().size())) choice=CMath.s_int(s); } final Poll.PollResult R=new Poll.PollResult(mob.Name(),"",""+choice); if(CMath.bset(P.getFlags(),Poll.FLAG_VOTEBYIP)) { R.ip=mob.session().getAddress(); if((mob.playerStats()!=null)&&(mob.playerStats().getAccount()!=null)) R.ip+="\t"+mob.playerStats().getAccount().getAccountName(); } P.addVoteResult(R); } catch(final java.io.IOException x) { if(Log.isMaskedErrMsg(x.getMessage())) Log.errOut("Polls",x.getMessage()); else Log.errOut("Polls",x); } } @Override public void modifyVote(Poll P, MOB mob) throws java.io.IOException { if((mob.isMonster())||(!CMSecurity.isAllowedAnywhere(mob,CMSecurity.SecFlag.POLLS))) return; boolean ok=false; int showFlag=-1; if(CMProps.getIntVar(CMProps.Int.EDITORTYPE)>0) showFlag=-999; final String oldName=P.getName(); while(!ok) { int showNumber=0; String possName=CMLib.genEd().prompt(mob,P.getName(),++showNumber,showFlag,L("Name")); while((!possName.equalsIgnoreCase(P.getName()))&&(CMLib.polls().getPoll(possName)!=null)) possName=possName+"!"; P.setName(possName); P.setDescription(CMLib.genEd().prompt(mob,P.getDescription(),++showNumber,showFlag,L("Introduction"))); P.setSubject(CMLib.genEd().prompt(mob,P.getSubject(),++showNumber,showFlag,L("Results Header"))); if(P.getSubject().length()>250) P.setSubject(P.getSubject().substring(0,250)); if(P.getAuthor().length()==0) P.setAuthor(mob.Name()); P.setQualZapper(CMLib.genEd().prompt(mob,P.getQualZapper(),++showNumber,showFlag,L("Qual. Mask"),true)); P.setFlags((CMLib.genEd().prompt(mob,CMath.bset(P.getFlags(),Poll.FLAG_ACTIVE),++showNumber,showFlag,L("Poll Active")))? CMath.setb(P.getFlags(),Poll.FLAG_ACTIVE):CMath.unsetb(P.getFlags(),Poll.FLAG_ACTIVE)); P.setFlags((CMLib.genEd().prompt(mob,CMath.bset(P.getFlags(),Poll.FLAG_PREVIEWRESULTS),++showNumber,showFlag,L("Preview Results")))? CMath.setb(P.getFlags(),Poll.FLAG_PREVIEWRESULTS):CMath.unsetb(P.getFlags(),Poll.FLAG_PREVIEWRESULTS)); P.setFlags((CMLib.genEd().prompt(mob,CMath.bset(P.getFlags(),Poll.FLAG_ABSTAIN),++showNumber,showFlag,L("Allow Abstention")))? CMath.setb(P.getFlags(),Poll.FLAG_ABSTAIN):CMath.unsetb(P.getFlags(),Poll.FLAG_ABSTAIN)); P.setFlags((CMLib.genEd().prompt(mob,CMath.bset(P.getFlags(),Poll.FLAG_VOTEBYIP),++showNumber,showFlag,L("Use IP Addresses/Accounts")))? CMath.setb(P.getFlags(),Poll.FLAG_VOTEBYIP):CMath.unsetb(P.getFlags(),Poll.FLAG_VOTEBYIP)); P.setFlags((CMLib.genEd().prompt(mob,CMath.bset(P.getFlags(),Poll.FLAG_HIDERESULTS),++showNumber,showFlag,L("Hide Results")))? CMath.setb(P.getFlags(),Poll.FLAG_HIDERESULTS):CMath.unsetb(P.getFlags(),Poll.FLAG_HIDERESULTS)); P.setFlags((CMLib.genEd().prompt(mob,CMath.bset(P.getFlags(),Poll.FLAG_NOTATLOGIN),++showNumber,showFlag,L("POLL CMD only")))? CMath.setb(P.getFlags(),Poll.FLAG_NOTATLOGIN):CMath.unsetb(P.getFlags(),Poll.FLAG_NOTATLOGIN)); String expirationDate="NA"; if(P.getExpiration()>0) expirationDate=CMLib.time().date2String(P.getExpiration()); expirationDate=CMLib.genEd().prompt(mob,expirationDate,++showNumber,showFlag,L("Exp. Date (MM/DD/YYYY HH:MM AP)"),true); if((expirationDate.trim().length()==0)||(expirationDate.equalsIgnoreCase("NA"))) P.setExpiration(0); else { try{P.setExpiration(CMLib.time().string2Millis(expirationDate.trim()));}catch(final Exception e){}} final Vector<Poll.PollOption> del=new Vector<Poll.PollOption>(); for(int i=0;i<P.getOptions().size();i++) { final Poll.PollOption PO=P.getOptions().get(i); PO.text=CMLib.genEd().prompt(mob,PO.text,++showNumber,showFlag,L("Vote Option"),true); if(PO.text.length()==0) del.addElement(PO); } for(int i=0;i<del.size();i++) P.getOptions().remove(del.elementAt(i)); Poll.PollOption PO=null; while(!mob.session().isStopped()) { PO=new Poll.PollOption( CMLib.genEd().prompt(mob,"",++showNumber,showFlag,L("New Vote Option"),true) ); if(PO.text.length()==0) break; P.getOptions().add(PO); } if(showFlag<-900){ ok=true; break;} if(showFlag>0){ showFlag=-1; continue;} showFlag=CMath.s_int(mob.session().prompt(L("Edit which? "),"")); if(showFlag<=0) { showFlag=-1; ok=true; } } updatePoll(oldName,P); } @Override public void processResults(Poll P, MOB mob) { if(!P.mayISeeResults(mob)) return; if(!loadPollIfNecessary(P)) return; final StringBuffer present=new StringBuffer(""); present.append("^O"+P.getSubject()+"^N\n\r\n\r"); if(P.getOptions().size()==0) { mob.tell(L("@x1Oops! No options defined!",present.toString())); return; } int total=0; final int[] votes=new int[P.getOptions().size()+(CMath.bset(P.getFlags(),Poll.FLAG_ABSTAIN)?1:0)]; Poll.PollResult R=null; int choice=0; for(int r=0;r<P.getResults().size();r++) { R=P.getResults().get(r); choice=CMath.s_int(R.answer); if(((choice<=0)&&CMath.bset(P.getFlags(),Poll.FLAG_ABSTAIN)) ||((choice>=0)&&(choice<=P.getOptions().size()))) { total++; if(choice<=0) votes[votes.length-1]++; else votes[choice-1]++; } } Poll.PollOption O=null; for(int o=0;o<P.getOptions().size();o++) { O=P.getOptions().get(o); int pct=0; if(total>0) pct=(int)Math.round(CMath.div(votes[o],total)*100.0); present.append(CMStrings.padRight("^H"+(o+1),2)+": ^N"+O.text+" ^O(Votes: "+votes[o]+" - "+pct+"%)^N\n\r"); } if(CMath.bset(P.getFlags(),Poll.FLAG_ABSTAIN)) { int pct=0; if(total>0) pct=(int)Math.round(CMath.div(votes[votes.length-1],total)*100.0); present.append(" ^NAbstentions ^O("+votes[votes.length-1]+" - "+pct+"%)^N\n\r"); } mob.tell(present.toString()); } @Override public void createPoll(Poll P) { addPoll(P); CMLib.database().DBCreatePoll(P.getName(), P.getAuthor(), P.getSubject(), P.getDescription(), P.getOptionsXML(), (int)P.getFlags(), P.getQualZapper(), P.getResultsXML(), P.getExpiration()); } @Override public void updatePollResults(Poll P) { CMLib.database().DBUpdatePollResults(P.getName(),P.getResultsXML()); } @Override public void updatePoll(String oldName, Poll P) { CMLib.database().DBUpdatePoll(oldName, P.getName(), P.getAuthor(), P.getSubject(), P.getDescription(), P.getOptionsXML(), (int)P.getFlags(), P.getQualZapper(), P.getResultsXML(), P.getExpiration()); } @Override public void deletePoll(Poll P) { removePoll(P); CMLib.database().DBDeletePoll(P.getName()); } @Override public boolean loadPollIfNecessary(Poll P) { if(P.loaded()) return true; final DatabaseEngine.PollData data =CMLib.database().DBReadPoll(P.getName()); if(data==null) return false; P.setName(data.name()); P.setAuthor(data.byName()); P.setSubject(data.subject()); P.setDescription(data.description()); final Vector<Poll.PollOption> options=new Vector<Poll.PollOption>(); P.setOptions(options); final String optionsXML=data.options(); List<XMLLibrary.XMLTag> V2=CMLib.xml().parseAllXML(optionsXML); XMLTag OXV=CMLib.xml().getPieceFromPieces(V2,"OPTIONS"); if((OXV!=null)&&(OXV.contents()!=null)&&(OXV.contents().size()>0)) for(int v2=0;v2<OXV.contents().size();v2++) { final XMLTag XP=OXV.contents().get(v2); if(!XP.tag().equalsIgnoreCase("option")) continue; final Poll.PollOption PO=new Poll.PollOption( CMLib.xml().restoreAngleBrackets(XP.getValFromPieces("TEXT")) ); options.addElement(PO); } P.setFlags(data.flag()); P.setQualZapper(data.qual()); final Vector<Poll.PollResult> results=new Vector<Poll.PollResult>(); P.setResults(results); final String resultsXML=data.results(); V2=CMLib.xml().parseAllXML(resultsXML); OXV=CMLib.xml().getPieceFromPieces(V2,"RESULTS"); if((OXV!=null)&&(OXV.contents()!=null)&&(OXV.contents().size()>0)) for(int v2=0;v2<OXV.contents().size();v2++) { final XMLTag XP=OXV.contents().get(v2); if(!XP.tag().equalsIgnoreCase("result")) continue; final Poll.PollResult PR=new Poll.PollResult( XP.getValFromPieces("USER"), XP.getValFromPieces("IP"), XP.getValFromPieces("ANS")); results.addElement(PR); } P.setExpiration(data.expiration()); P.setLoaded(true); return true; } @Override public Poll loadPollByName(String name) { final Poll P=(Poll)CMClass.getCommon("DefaultPoll"); P.setLoaded(false); P.setName(name); return loadPollIfNecessary(P)?P:null; } }