package net.taehui.twilight import com.google.protobuf.ByteString import io.netty.channel.ChannelFuture import io.netty.channel.ChannelHandlerContext import net.taehui.EventClass import net.taehui.twilight.qwilight.QwilightAvatar import net.taehui.twilight.system.AvatarHandler import net.taehui.twilight.system.DB import net.taehui.twilight.system.LanguageSystem import net.taehui.twilight.system.SiteHandler import java.net.InetAddress import java.time.LocalDateTime import java.util.* interface Avatar : AutoCloseable, Logger { val availableCSX: Any val siteYellMillis: LinkedList<Long> var lastSignInDate: LocalDateTime var handler: ChannelHandlerContext var isAwilight: Boolean var isAvailable: Boolean val isEnterQuitAware: Boolean var isSignedIn: Boolean var isEstablished: Boolean var avatarID: String var avatarName: String var avatarEstimatedID: String var avatarIP: InetAddress var language: String var situationValue: Int var situationText: String var isValve: Boolean var avatarCompetence: Int var qwilightHash: String var qwilightDate: String var qwilightID: String var qwilightName: String val avatarNameTitle: String val loggerID: String fun doIfValid(event: EventClass.Event, onValid: () -> Unit) { val millis = System.currentTimeMillis() if (millis < 10 * 60 * 1000 + event.millis) { if (event.eventID == EventClass.Event.EventID.ESTABLISH || avatarID == event.avatarID) { onValid() } else { logInfo("$avatarID != ${event.avatarID}") } } else { logInfo("$millis << ${event.millis}") } } fun doIfAvailable(onAvailable: () -> Unit) { synchronized(availableCSX) { if (isAvailable) { onAvailable() } } } fun wantSignedIn(toHandle: (String) -> Unit) { wantEstablished { if (isSignedIn) { toHandle(it) } } } fun wantNotSignedIn(toHandle: () -> Unit) { wantEstablished { if (!isSignedIn) { toHandle() } } } fun wantEstablished(toHandle: (String) -> Unit) { if (isEstablished) { toHandle(avatarID) } } fun wantNotEstablished(toHandle: () -> Unit) { if (!isEstablished) { toHandle() } } val remote: String get() = avatarIP.hostAddress fun translateLanguage(target: String): String { return LanguageSystem.getLanguage(language, target) } val isSU: Boolean get() = avatarCompetence == 2 fun isMillisSuitable(targetMillis: Long): Boolean { if (siteYellMillis.size >= 5) { val millis = siteYellMillis.poll() siteYellMillis.offer(targetMillis) return targetMillis - millis >= 5000 } siteYellMillis.offer(targetMillis) return true } fun allowSignIn(): Boolean { return LocalDateTime.now().minusSeconds(1).isAfter(lastSignInDate) } fun trySignInDate() { lastSignInDate = LocalDateTime.now() } fun handleNotSignIn() { if (isSignedIn) { SiteHandler.quitAvatar(this) isSignedIn = false avatarID = qwilightID avatarName = avatarNameTitle + qwilightName avatarCompetence = 1 setLastDate() send(EventClass.Event.EventID.NOT_SIGN_IN, object { val avatarID = this@Avatar.avatarID val avatarName = this@Avatar.avatarName }) } } fun setLastDate() { if (isSignedIn && !isAwilight) { DB.setLastDate(Utility.getDefaultAvatarID(avatarID)) } } fun doNewSite(siteData: JSON.QwilightNewSite) { if (siteData.siteName.isNotEmpty() && !siteData.siteName.startsWith("@")) { val siteID = UUID.randomUUID() if (siteData.isNetSite) { SiteHandler.putNetSite(this, siteID, siteData) } else { SiteHandler.putSite(this, siteID, siteData) } } else { send(EventClass.Event.EventID.WARNING, translateLanguage("siteNameNotValid")) } } fun doNewSilentSite(targetAvatarID: String) { if (Utility.getDefaultAvatarID(avatarID) == Utility.getDefaultAvatarID( targetAvatarID ) ) { send(EventClass.Event.EventID.WARNING, translateLanguage("silentSiteAvatarIsYou")) } else { AvatarHandler.getAvatar(targetAvatarID)?.let { avatar -> DB.getSilentSiteCompetence( Utility.getDefaultAvatarID( targetAvatarID ) ).thenAccept { if (isSignedIn) { if (it == QwilightAvatar.SILENT_SITE_CALLABLE || it == QwilightAvatar.SILENT_SITE_AVATAR && isSignedIn || it == QwilightAvatar.SILENT_SITE_UBUNTU && DB.isCrossUbuntu( avatarID, targetAvatarID ) ) { SiteHandler.putSilentSite(this, avatar) } else { send(EventClass.Event.EventID.WARNING, translateLanguage("lowerCompetenceAsSilentSite")) } } else { send(EventClass.Event.EventID.WARNING, translateLanguage("silentSiteAvatarIsNotSignedIn")) } } } } } fun setSiteName(siteID: String, siteName: String) { if (siteName.isNotEmpty() && !siteName.startsWith("@")) { SiteHandler.setSiteName(this, UUID.fromString(siteID), siteName) } else { send(EventClass.Event.EventID.WARNING, translateLanguage("siteNameNotValid")) } } fun handleSignIn(totem: String, avatarID: String, avatarName: String, avatarCompetence: Int) { if (!isSignedIn) { SiteHandler.quitAvatar(this) isSignedIn = true this.avatarID = avatarID this.avatarName = avatarNameTitle + avatarName this.avatarCompetence = avatarCompetence setLastDate() send(EventClass.Event.EventID.SIGN_IN, object { val totem = totem val avatarID = avatarID val avatarName = avatarName }) } } fun setEstablished(avatarID: String, qwilightName: String, isValve: Boolean) { isEstablished = true qwilightID = avatarID this.qwilightName = qwilightName this.isValve = isValve this.avatarID = qwilightID avatarName = avatarNameTitle + this.qwilightName send(EventClass.Event.EventID.ESTABLISH, object { val avatarID = avatarID val avatarName = this@Avatar.avatarName }) } fun send(eventID: EventClass.Event.EventID, text: Any?, vararg data: ByteString?): ChannelFuture fun send(event: EventClass.Event) override fun close() { handler.close() } }