001/*
002 * Copyright (c) 2009 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016package org.opengion.plugin.column;
017
018import java.text.DecimalFormat;
019
020import org.opengion.fukurou.util.StringUtil;
021import org.opengion.hayabusa.db.AbstractRenderer;
022import org.opengion.hayabusa.db.CellRenderer;
023import org.opengion.hayabusa.db.DBColumn;
024
025/**
026 * UNIT レンデラーは、カラムのデータの単位変換を行う場合に使用するクラスです。
027 *
028 * マイナス表示はありません。
029 * 単位は、RendererParam で指定します。
030 * 単位の自動変換を(ある程度)サポートします。
031 * KB,MB,GB,TB は、それぞれを、1024の倍数で割り算して求めます。
032 * それ以外では、K*,M*,G* に対して、先頭文字で判断して、1000の倍数で割り算します。
033 * それ以外の単位変換は、サポートしていません。
034 * (数値の後ろに変換なしで文字列を付けるだけです。)
035 *
036 * 負数の場合はspanタグclass="minus"を付けて出力します。
037 *
038 * 単位変換時の小数点は切り上げします。ただし、データが nullかゼロ文字列か、0 の場合は、0 になります。
039 * 1Byteのファイルの場合は、1 KB という表示になります。
040 *
041 * カラムの表示に必要な属性は、DBColumn オブジェクト より取り出します。
042 * このクラスは、DBColumn オブジェクト毎に1つ作成されます。
043 *
044 * @og.group データ表示
045 * @og.rev 7.2.3.1 (2020/04/17) 新規追加
046 *
047 * @version  7.2
048 * @author       Kazuhiko Hasegawa
049 * @since    JDK11.0,
050 */
051public class Renderer_UNIT extends AbstractRenderer {
052        /** このプログラムのVERSION文字列を設定します。   {@value} */
053        private static final String VERSION = "8.5.5.1 (2024/02/29)";
054
055        private static final DecimalFormat FMT1 = new DecimalFormat( "#,##0" );
056
057        private final String    unit ;
058        private final long              division ;
059
060        /**
061         * デフォルトコンストラクター。
062         * このコンストラクターで、基本オブジェクトを作成します。
063         *
064         * @og.rev 7.2.3.1 (2020/04/17) Renderer_UNIT 新規追加
065         *
066         */
067        public Renderer_UNIT() {
068                this( "",1L );
069        }
070
071        /**
072         * コンストラクター
073         *
074         * @og.rev 7.2.3.1 (2020/04/17) Renderer_UNIT 新規追加
075         *
076         * @param       tani    単位記号
077         * @param       div             単位換算の除数
078         */
079        private Renderer_UNIT( final String tani,final long div ) {
080                super();
081                unit             = tani;
082                division         = div;
083        }
084
085        /**
086         * 各オブジェクトから自分のインスタンスを返します。
087         * 自分自身をキャッシュするのか、新たに作成するのかは、各サブクラスの実装に
088         * まかされます。
089         *
090         * @og.rev 7.2.3.1 (2020/04/17) Renderer_UNIT 新規追加
091         * @og.rev 8.5.5.1 (2024/02/29) switch式の使用
092         *
093         * @param       clm     DBColumnオブジェクト
094         *
095         * @return      CellRendererオブジェクト
096         * @og.rtnNotNull
097         */
098        public CellRenderer newInstance( final DBColumn clm ) {
099                // 単位は、RendererParamから取得
100                final String tani = StringUtil.nval( clm.getRendererParam() , "" );
101
102                long div = 1L;
103
104                // KB,MB,GB,TB は、それぞれを、1024の倍数で割り算して求めます。
105                // それ以外では、K*,M*,G* に対して、先頭文字で判断して、1000の倍数で割り算します。
106                if( !tani.isEmpty() ) {
107                        final char ch1 = tani.charAt(0);                // 最初の文字(K,M,G,T)
108                        final int base = tani.length() >= 2 && tani.charAt(1) == 'B' ? 1024 : 1000 ;
109
110                        // 8.5.5.1 (2024/02/29) switch式の使用
111//                      switch( ch1 ) {
112//                              case 'K' : div = base; break;
113//                              case 'M' : div = base*base; break;
114//                              case 'G' : div = base*base*base; break;
115//                              case 'T' : div = base*base*base*base; break;
116//                              default  : div = 1L; break;
117//                      }
118                        div = switch( ch1 ) {
119                                case 'K' -> div = base;
120                                case 'M' -> div = base*base;
121                                case 'G' -> div = base*base*base;
122                                case 'T' -> div = base*base*base*base;
123                                default  -> div = 1L;
124                        };
125                }
126
127                return new Renderer_UNIT( tani,div );
128        }
129
130        /**
131         * データの表示用文字列を返します。
132         *
133         * @og.rev 7.2.3.1 (2020/04/17) Renderer_UNIT 新規追加
134         *
135         * @param       value 入力値(『数字型文字列』)
136         *
137         * @return      データの表示用文字列
138         * @og.rtnNotNull
139         */
140        @Override
141        public String getValue( final String value ) {
142                return getValue( value , true );
143        }
144
145        /**
146         * データ出力用の文字列を作成します。
147         * ファイル等に出力する形式を想定しますので、HTMLタグを含まない
148         * 生データを返します。
149         * 基本は、#getValue( String ) をそのまま返します。
150         *
151         * @og.rev 7.2.3.1 (2020/04/17) Renderer_UNIT 新規追加
152         *
153         * @param       value 入力値(『数字型文字列』)
154         *
155         * @return  データ出力用の文字列(数字型文字列 のみ)
156         * @og.rtnNotNull
157         * @see         #getValue( String )
158         */
159        @Override
160        public String getWriteValue( final String value ) {
161                return getValue( value , false );
162        }
163
164        /**
165         * データ表示用/出力用の文字列を作成します。
166         * 第二引数の isView == true で、データ表示用文字列を、false で
167         * データ出力用の文字列を作成します。
168         * 処理の共通化を行うためのメソッドです。
169         *
170         * @og.rev 7.2.3.1 (2020/04/17) Renderer_UNIT 新規追加
171         *
172         * @param       value 入力値(『数字型文字列』)
173         * @param   isView データ表示用かどうか(true:表示用/false:出力用)
174         *
175         * @return  データ表示用/出力用の文字列
176         * @og.rtnNotNull
177         * @see         #getValue( String )
178         */
179        private String getValue( final String value , final boolean isView ) {
180                // 8.5.4.2 (2024/01/12) PMD 7.0.0 InefficientEmptyStringCheck 対応
181//              String rtn = value == null || value.trim().isEmpty() ? "0" : value ;
182                String rtn = StringUtil.isNull( value ) ? "0" : value ;
183
184                final long val = ( Long.parseLong( rtn ) + division - 1 ) / division ;          // 切り上げ
185
186                synchronized( FMT1 ) {                                                  // 7.2.9.5 (2020/11/28)
187                        rtn = FMT1.format( val ) + " " + unit ;
188                }
189
190                // 8.5.5.1 (2024/02/29) PMD 7.0.0 OnlyOneReturn メソッドには終了ポイントが 1 つだけ必要
191//              if( !isView ) { return rtn; }                                   // 6.2.0.0 (2015/02/27) マイナス記号のまま
192
193//              if( StringUtil.startsChar( rtn , '-' ) ) {
194                if( isView && StringUtil.startsChar( rtn , '-' ) ) {
195                        rtn = "<span class=\"minus\">" + rtn + "</span>";
196                }
197                return rtn;
198        }
199}